第一题
HDU1698http://acm.hdu.edu.cn/showproblem.php?pid=1698
这是在区间上进行整段的修改操作,我们就用to[]数组代表修改的lazy标记
记住在构建树和在change函数中自顶向下更新的时候,一定要注意重新回去更新上层的节点,所以末尾需加上update(cur)
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 #define N 100005 5 int sum[4*N],to[4*N]; 6 7 void update(int x) 8 { 9 sum[x]=sum[x<<1]+sum[x<<1|1]; 10 } 11 void build(int cur,int x,int y) 12 { 13 int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1; 14 to[cur]=0; 15 if(x==y){ 16 sum[cur]=1; 17 return; 18 } 19 build(ls,x,mid); 20 build(rs,mid+1,y); 21 update(cur); 22 } 23 void pushdown(int cur,int x,int y) 24 { 25 int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1; 26 if(to[cur]!=0){ 27 to[ls]=to[rs]=to[cur]; 28 sum[ls]=(mid-x+1)*to[cur]; 29 sum[rs]=(y-mid)*to[cur]; 30 to[cur]=0; 31 } 32 } 33 void change(int cur,int x,int y,int s,int t,int v) 34 { 35 int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1; 36 if(x>=s&&y<=t){ 37 sum[cur]=(y-x+1)*v; 38 to[cur]=v; 39 return; 40 } 41 pushdown(cur,x,y); 42 if(mid>=s) change(ls,x,mid,s,t,v); 43 if(mid+1<=t) change(rs,mid+1,y,s,t,v); 44 update(cur); 45 } 46 void query(int cur,int x,int y,int s,int t,int &ans) 47 { 48 int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1; 49 if(x>=s&&y<=t){ 50 ans+=sum[cur]; 51 return; 52 } 53 pushdown(cur,x,y); 54 if(mid>=s) query(ls,x,mid,s,t,ans); 55 if(mid+1<=t) query(rs,mid+1,y,s,t,ans); 56 } 57 int main() 58 { 59 int T,n,Q,a,b,c,ans; 60 scanf("%d",&T); 61 for(int i=1;i<=T;i++){ 62 ans=0; 63 scanf("%d%d",&n,&Q); 64 build(1,1,n); 65 for(int j=0;j<Q;j++){ 66 scanf("%d%d%d",&a,&b,&c); 67 change(1,1,n,a,b,c); 68 } 69 query(1,1,n,1,n,ans); 70 printf("Case %d: The total value of the hook is %d. ",i,ans); 71 } 72 return 0; 73 }
第二题
POJ3468http://poj.org/problem?id=3468
这是在一段区间上添加值,所以与上题的操作不一样,对于每个相加的数,我们应该也不断将lazy节点累加,类似这种的累加操作,我们总是选择
用add[]数组作为lazy标记
当然这道题特别坑的是因为在累加过程中可以达到10000*100000这样子就超过了int的类型,我们就要用LL来定义sum[],add[]和ans
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 #define N 100005 6 #define LL long long 7 int a[N]; 8 LL sum[4*N],add[4*N]; 9 void update(int x) 10 { 11 sum[x]=sum[x<<1]+sum[x<<1|1]; 12 } 13 void build(int cur,int x,int y) 14 { 15 add[cur]=0; 16 int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1; 17 if(x==y){ 18 sum[cur]=a[x]; 19 return; 20 } 21 build(ls,x,mid); 22 build(rs,mid+1,y); 23 update(cur); 24 } 25 void pushdown(int cur,int x,int y) 26 { 27 int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1; 28 if(add[cur]!=0){ 29 add[ls]+=add[cur]; 30 add[rs]+=add[cur]; 31 sum[ls]+=(mid-x+1)*add[cur]; 32 sum[rs]+=(y-mid)*add[cur]; 33 add[cur]=0; 34 } 35 } 36 void change(int cur,int x,int y,int s,int t,int v) 37 { 38 int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1; 39 if(x>=s&&y<=t){ 40 sum[cur]+=(y-x+1)*v; 41 add[cur]+=v; 42 return; 43 } 44 pushdown(cur,x,y); 45 if(mid>=s) change(ls,x,mid,s,t,v); 46 if(mid<t) change(rs,mid+1,y,s,t,v); 47 update(cur); 48 } 49 void query(int cur,int x,int y,int s,int t,LL &ans) 50 { 51 int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1; 52 if(x>=s&&y<=t){ 53 ans+=sum[cur]; 54 return; 55 } 56 pushdown(cur,x,y); 57 if(mid>=s) query(ls,x,mid,s,t,ans); 58 if(mid<t) query(rs,mid+1,y,s,t,ans); 59 } 60 int main() 61 { 62 int q,n,x,y,z; 63 char c; 64 while(scanf("%d%d",&n,&q)!=EOF){ 65 for(int i=1;i<=n;i++) scanf("%d",&a[i]); 66 build(1,1,n); 67 for(int i=1;i<=q;i++){ 68 cin>>c; 69 if(c=='C'){ 70 scanf("%d%d%d",&x,&y,&z); 71 change(1,1,n,x,y,z); 72 } 73 else{ 74 scanf("%d%d",&x,&y); 75 LL ans=0; 76 query(1,1,n,x,y,ans); 77 printf("%I64d ",ans); 78 } 79 } 80 } 81 return 0; 82 }
第三题
这是对于是否整除3的数的个数求和,这里用add[]不断累加lazy标记,但是要分情况讨论余1,余2两种情况
SPOJ MULTQ3 这道题目特别容易超时。。。我就不吐槽我自己一会提交成功一会TLE了,感觉要看运气~~
这道题目主要考虑在pushdown上面的修改,因为是否为3的整数倍,中间有余1和余2两种情况要进行考虑
另外我们增添两个数组来保存余1和余2的个数,当然你也可以考虑用2维数组,这里情况比较少,多建几个数组也不是很麻烦
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define N 100005 int sum1[4*N],sum2[4*N],sum3[4*N],a[N],add[4*N]; void update(int cur) { sum1[cur]=sum1[cur<<1]+sum1[cur<<1|1]; sum2[cur]=sum2[cur<<1]+sum2[cur<<1|1]; sum3[cur]=sum3[cur<<1]+sum3[cur<<1|1]; } void build(int cur,int x,int y) { add[cur]=0; int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1; if(x==y){ sum1[cur]=1; sum2[cur]=0; sum3[cur]=0; return; } build(ls,x,mid); build(rs,mid+1,y); update(cur); } void pushdown(int cur,int x,int y) { int ls=cur<<1,rs=cur<<1|1; if(add[cur]%3!=0) { add[ls]+=add[cur],add[rs]+=add[cur]; if(add[cur]%3==1){ int temp=sum1[ls]; sum1[ls]=sum3[ls]; sum3[ls]=sum2[ls]; sum2[ls]=temp; temp=sum1[rs]; sum1[rs]=sum3[rs]; sum3[rs]=sum2[rs]; sum2[rs]=temp; } else if(add[cur]%3==2){ int temp=sum2[ls]; sum2[ls]=sum3[ls]; sum3[ls]=sum1[ls]; sum1[ls]=temp; temp=sum2[rs]; sum2[rs]=sum3[rs]; sum3[rs]=sum1[rs]; sum1[rs]=temp; } add[cur]=0; } } void change(int cur,int x,int y,int s,int t,int v) { int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1; if(x>=s&&y<=t){ int temp; temp=sum1[cur]; sum1[cur]=sum3[cur]; sum3[cur]=sum2[cur]; sum2[cur]=temp; add[cur]+=v; return; } pushdown(cur,x,y); if(mid>=s) change(ls,x,mid,s,t,v); if(mid+1<=t) change(rs,mid+1,y,s,t,v); update(cur); } void query(int cur,int x,int y,int s,int t,int &ans) { int mid=(x+y)/2,ls=cur<<1,rs=cur<<1|1; if(x>=s&&y<=t){ ans+=sum1[cur]; return; } pushdown(cur,x,y); if(mid>=s) query(ls,x,mid,s,t,ans); if(mid+1<=t) query(rs,mid+1,y,s,t,ans); } int main() { int n,q,log,a,b; while(scanf("%d%d",&n,&q)!=EOF){ build(1,0,n-1); for(int i=0;i<q;i++){ scanf("%d",&log); if(log==0){ scanf("%d%d",&a,&b); change(1,0,n-1,a,b,1); } else{ scanf("%d%d",&a,&b); int ans=0; query(1,0,n-1,a,b,ans); printf("%d ",ans); } } } return 0; }