!
题意
给定区间 q查询l r c l r 更新加d 然后带一个时间戳 加1 然后 h 询问l到r 在t时间戳 b 把时间戳改为t
题意
标准在线主席树啊,树上维护的不是权值线段树,而是对应的正常的树
然后,怎么处理区间更新呢 ,我们都知道,主席树是根据之前的树,来对之前的结点复用也好
总之相当于多一颗树,我们单点修改的好说,只是影响一条链,但是区间更新怎么办
我们可以想到打标记 lazy,但是我们怎么,更新的时候怎么pushup 呢,这个好处理
我们可以发现 我们树从上往下的结构嘛,所以在递归的时候,可以把这个父节点的sum,直接更新
这样省去了pushup 其实也差不多,主要是 怎么处理pushdown 因为你没办法往下传lazy,
这样就会多开结点,相当于你多开了区间这么多结点,直接mle啊
空间爆炸,所以我们要考虑 不pushdown,我们可以从上往下,对树遍历的时候,找完全是你要找的区间
并且在树上有的,就是递归的时候 写三个的那种,
完全是左边r<=mid 就在递归左,完全是右 l>mid 就递归右
然后,中间区间的话,在拆开递归,l到mid,mid+1到r
这样,更新的时候,判断l==L,r==R,这样保证你更新的区间,一定是你要找的区间
然后对应的,我们在更新的时候,sum已经更新完了,加上你更新的值和对区间的影响长度,
即R-L+1,然后,我们呢把完全要找的区间打一个lazy
然后,在查询的时候,我们从上往下的时候,把所有要找的区间lazy算一下,加上去,
这样保证一定是对的,
举个例子 比如 1-10 我更新 1-7 那么 树上影响的区间
1-10
1-5,6-10
6-8
6-7
这几个区间吧,我们在从上往下递归的时候,已经把他们的和都更新过了
然后,我们对于1-5,6-7 这几个区间打了lazy
然后当我们查询的时候,假如找1-4
因为和已经更新过了,所以 1-3的和直接返回就可以
然后找到4-5的时候,接下来递归4,这个时候
正常的操作是 pushdown 标记下传 ,但是我们可以不传标记,
直接把标记的值乘上要找的区间长度 ,加上就可以了
因为你是三个判断的那种递归,保证你找的区间一定是对应要找的长度,所以这样写没有问题
AC代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100000 + 5;
#define ll long long
ll a[N] ;
int rt[N * 35], ls[N * 35], rs[N * 35];
ll lazy[N*35];
ll sum [N * 35];
int tot;
void Build(int &o, int l, int r)
{
o = ++ tot;
sum[o] = a[l];
lazy[o] = 0;
if(l == r) return;
int m = (l + r) >> 1;
Build(ls[o], l, m);
Build(rs[o], m + 1, r);
sum[o] = sum[ls[o]] + sum[rs[o]];
}
void update(int &o, int l, int r, int last, int L, int R, ll val)
{
o = ++ tot;
ls[o] = ls[last];
rs[o] = rs[last];
lazy[o] = lazy[last];
sum[o] = sum[last]+val*(R-L+1); //把每个区间的增量都算上 这一步省去了pushup
if(L==l&&r==R)
{
lazy[o] += val; //完全是要找区间的并且是完整的一个区间的更新lazy
return ;
}
int m = (l + r) >> 1;
if(R<=m) update(ls[o],l,m,ls[last],L,R,val);
else if(L>m) update(rs[o],m+1,r,rs[last],L,R,val);
else
{
update(ls[o],l,m,ls[last],L,m,val);
update(rs[o],m+1,r,rs[last],m+1,R,val);
}
}
ll query(int ss, int l, int r, int L,int R)
{
if(L<=l&&r<=R)
{
return sum[ss];
}
ll ans = lazy[ss]*(R-L+1); // 每次往下找的时候 把这个区间的lazy对最后和的影响算一下 这一步省去了pushdown
int m = (l + r) >> 1;
if(R<=m) ans+=query(ls[ss],l,m,L,R);
else if(L>m) ans+=query(rs[ss],m+1,r,L,R);
else
{
ans+=query(ls[ss],l,m,L,m);
ans+=query(rs[ss],m+1,r,m+1,R);
}
return ans;
}
int main()
{
int n,q;
while(scanf("%d%d", &n, &q)==2)
{
for(int i = 1; i <= n; i ++)
{
scanf("%lld",&a[i]);
}
tot = 0;
int sz = n;
Build(rt[0],1, sz);
int time = 0 ;
char s[15];
int ql,qr;
while(q--)
{
scanf("%s",s);
if(s[0]=='Q')
{
scanf("%d%d", &ql, &qr);
printf("%lld\n",query(rt[time],1,sz,ql,qr));
}
else if(s[0]=='C')
{
ll val;
scanf("%d%d%lld", &ql, &qr,&val);
update(rt[time+1],1,sz,rt[time],ql,qr,val);
time++;
}
else if(s[0]=='H')
{
int time1;
scanf("%d%d%d", &ql, &qr,&time1);
printf("%lld\n",query(rt[time1],1,sz,ql,qr));
}
else if(s[0]=='B')
{
scanf("%d",&time);
}
}
}
}