[COGS 2632] [HZOI 2016] 数列操作d
book
归档:
OI
flag
题目描述
原题地址:COGS
思路
很显然是线段树
节点定义
对于每个节点,维护当前区间的首项,公差,区间和
下放标记
注意左右节点的标记不同:
用有序数对$(first,delta)$来表示首项,公差。
则左儿子的信息为$(first,delta)$,右儿子的信息为$(first+length\times delta,delta)$,若用$[l,r]$表示整个区间,$m=\frac{l+r}{2}$,则$length=m-l+1$。
接着,用标记更新答案,注意应该用父节点的标记更新,类似
root -> lc -> sum += ...
完成之后删除父节点的标记
查询
查询没什么好说的
标准的线段树
修改
这个就很恶心
由于等差数列的存在,将待查询区间划分成两个小区间时要记录当前操作区间的首项
到达可以修改的区间时,修改$delta,first$,更新$sum$
然后递归维护左右子树信息
写了半天感觉我的代码没毛病啊为什么A不了qwq
好吧是我的等差数列求和写错了。。
代码
#include<bits/stdc++.h>
using namespace std;
#define m ((l + r) >> 1)
typedef long long ll;
const int mod = 1e9 + 7;
struct node
{
ll sum, fst, delt;
node *lc, *rc;
node() { sum = fst = delt = 0, lc = rc = 0; }
void mt(int l, int r, ll fst, ll delt)
{
this -> fst += fst;
this -> delt += delt;
this -> sum += fst * (r - l + 1);
this -> sum += (r - l + 1) * 1ll * (r - l) / 2 * delt;
}
};
node *build(int l, int r)
{
node *x = new node();
if (l == r)
return x;
x -> lc = build(l, m);
x -> rc = build(m + 1, r);
return x;
}
void pushd(node *x, int l, int r)
{
if (l == r) return;
if (x -> delt == 0 && x -> fst == 0) return;
x -> lc -> mt(l, m, x -> fst, x -> delt);
x -> rc -> mt(m + 1, r, x -> fst + (m - l + 1) * x -> delt, x -> delt);
x -> delt = x -> fst = 0;
}
ll query(node *x, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr)
return x -> sum;
pushd(x, l, r);
ll ans = 0;
if (ql <= m) ans += query(x -> lc, l, m, ql, qr);
if (m < qr) ans += query(x -> rc, m + 1, r, ql, qr);
return ans;
}
void update(node *x, int l, int r, int ql, int qr, ll val)
{
if (ql <= l && r <= qr)
{
x -> mt(l, r, val * (l - ql), val);
return;
}
pushd(x, l, r);
if (ql <= m) update(x -> lc, l, m, ql, qr, val);
if (m < qr) update(x -> rc, m + 1, r, ql, qr, val);
x -> sum = (x -> lc -> sum + x -> rc -> sum);
return;
}
int n, q;
int main()
{
freopen("segment.in", "r", stdin);
freopen("segment.out", "w", stdout);
ios::sync_with_stdio(0);
cin >> n >> q;
node *root = build(1, n);
for (int i = 1; i <= q; ++i)
{
int op, l, r, v;
cin >> op >> l >> r;
if (op)
{
cin >> v;
update(root, 1, n, l, r, v);
}
else cout << query(root, 1, n, l, r) % mod << endl;
}
}
写在最后
以后不太可能会去COGS上刷题了,也许刷COGS的人早已习惯了写的稀烂的题面,屎一样的格式和水水的数据。换句话说,你做的一切都是没有意义的。反倒是某些人。。。算了,就这样。总之就是我被恶心到了。
navigate_before
[洛谷 3379] [模板] 最近公共祖先(LCA)
[COGS 2745] 求GCD之和
navigate_next