题目:hdu4348.
题目大意:给定一个长度为
n
n
n的序列,要求支持以下操作
m
m
m次:
1.格式
C
 
l
 
r
 
d
C\,l\,r\,d
Clrd,表示给区间
[
l
,
r
]
[l,r]
[l,r]加上
d
d
d并给时刻
t
t
t加
1
1
1.
2.格式
Q
 
l
 
r
Q\,l\,r
Qlr,表示查询当前区间
[
l
,
r
]
[l,r]
[l,r]的和.
3.格式
H
 
l
 
r
 
t
H\,l\,r\,t
Hlrt,表示查询时刻
t
t
t时区间
[
l
,
r
]
[l,r]
[l,r]的和.
4.格式
B
 
t
B\,t
Bt,表示回到时刻
t
t
t.
1
≤
n
,
m
≤
1
0
5
1\leq n,m\leq 10^5
1≤n,m≤105.
这道题看起来可以直接可持久化搞,但是有一个问题是,如果打标机的话最多会影响 O ( n ) O(n) O(n)级别的节点,即使打上懒标记还是会在下传的时候出现问题,怎么办呢?
其实有一种技巧叫做永久化标记,就是打的标记不下传,查询的时候直接把顺路的标记也统计进去.
有了这种技巧,每次修改我们最多只会动用 O ( log n ) O(\log n) O(logn)个节点,这个时候我们就可以持久化了,具体可持久化过程与单点修改类似.
时空复杂度 O ( n + m log n ) O(n+m\log n) O(n+mlogn),建议最好开 4 n log n 4n\log n 4nlogn的空间,因为线段树区间修改最多会动用 4 log n 4\log n 4logn个节点,当然明显跑不满,实测开 30 n 30n 30n即可.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000,C=20;
char rc(){
char c=getchar();
for (;c<'A'||c>'Z';c=getchar());
return c;
}
int n,m;
LL a[N+9];
struct tree{
LL sum,tag;
int s[2];
}tr[N*C*4+9];
int cn,rot[N+9];
void Build(int L,int R,int &k=rot[0]){
tr[k=++cn]=tree();
if (L==R){tr[k].sum=a[L];return;}
int mid=L+R>>1;
Build(L,mid,tr[k].s[0]);Build(mid+1,R,tr[k].s[1]);
tr[k].sum=tr[tr[k].s[0]].sum+tr[tr[k].s[1]].sum;
}
void Add_tree(int L,int R,LL v,int l,int r,int hk,int &k){
tr[k=++cn]=tr[hk];
tr[k].sum+=v*(R-L+1);
if (l==L&&r==R){tr[k].tag+=v;return;}
int mid=l+r>>1;
if (R<=mid) Add_tree(L,R,v,l,mid,tr[hk].s[0],tr[k].s[0]);
else if (L>mid) Add_tree(L,R,v,mid+1,r,tr[hk].s[1],tr[k].s[1]);
else Add_tree(L,mid,v,l,mid,tr[hk].s[0],tr[k].s[0]),Add_tree(mid+1,R,v,mid+1,r,tr[hk].s[1],tr[k].s[1]);
}
LL Query_sum(int L,int R,int l,int r,int k){
if (l==L&&r==R) return tr[k].sum;
int mid=l+r>>1;
LL res=tr[k].tag*(R-L+1);
if (R<=mid) return Query_sum(L,R,l,mid,tr[k].s[0])+res;
else if (L>mid) return Query_sum(L,R,mid+1,r,tr[k].s[1])+res;
else return Query_sum(L,mid,l,mid,tr[k].s[0])+Query_sum(mid+1,R,mid+1,r,tr[k].s[1])+res;
}
Abigail into(){
for (int i=1;i<=n;++i)
scanf("%lld",&a[i]);
}
Abigail work(){
cn=0;
Build(1,n);
}
Abigail getans(){
int l,r,d,t=0;
while (m--)
switch (rc()){
case 'C':
scanf("%d%d%d",&l,&r,&d);
++t;
Add_tree(l,r,(LL)d,1,n,rot[t-1],rot[t]);
break;
case 'Q':
scanf("%d%d",&l,&r);
printf("%lld\n",Query_sum(l,r,1,n,rot[t]));
break;
case 'H':
scanf("%d%d%d",&l,&r,&d);
printf("%lld\n",Query_sum(l,r,1,n,rot[d]));
break;
case 'B':
scanf("%d",&t);
cn=rot[t+1]-1;
break;
}
}
int main(){
int cas=0;
while (~scanf("%d%d",&n,&m)){
into();
work();
if (cas) puts("");
++cas;
getans();
}
return 0;
}