这周学习了一下线段树,偶遇POJ 3468,这道题是线段树区间更新,题意大概是有一段的长为n的数组,经过若干次对其中某一段的数进行加减,询问某一段的和。这题还是比较明显的线段树,如果细分到对每一个节点进行操作的话,复杂度为O(m^logn),容易超时,所以采取延迟标记的做法,直接对某一段进行操作,而暂不对其子树进行操作,话不多说,直接上代码吧
#include<cstdio> #include<cstring> #include<cstdlib> #include <iostream> #include<algorithm> #include<cmath> using namespace std; struct node { int x,y,sign; long long sum,ad; } ; node tree[400010]; long long v[100010]; long long maketree(int x,int y,int z) { tree[z].x=x; tree[z].y=y; if(x>=y) return tree[z].sum=v[x]; else return tree[z].sum=maketree(x,(x+y)/2,2*z)+maketree((x+y)/2+1,y,2*z+1); } void down(int q) { tree[q].sign=0; tree[2*q].sign=tree[2*q+1].sign=1; tree[2*q].ad+=tree[q].ad; tree[2*q+1].ad+=tree[q].ad; tree[2*q].sum+=tree[q].ad*(tree[2*q].y-tree[2*q].x+1); tree[2*q+1].sum+=tree[q].ad*(tree[2*q+1].y-tree[2*q+1].x+1); tree[q].ad=0; } void add(int x,int y,int z,int q) { if(x<=tree[q].x&&y>=tree[q].y) { tree[q].sign=1; tree[q].sum+=z*(tree[q].y-tree[q].x+1); tree[q].ad+=z; return ; } if(tree[q].sign==1) down(q); if(x<=(tree[q].x+tree[q].y)/2) add(x,y,z,2*q); if(y>=(tree[q].x+tree[q].y)/2+1) add(x,y,z,2*q+1); tree[q].sum=tree[2*q].sum+tree[2*q+1].sum; return; } long long find(int x,int y,int q) { if(x>tree[q].y||y<tree[q].x) return 0; if(x<=tree[q].x&&y>=tree[q].y) return tree[q].sum; if(tree[q].sign==1) down(q); return find(x,y,2*q)+find(x,y,2*q+1); } int main() { int n,q,x,y,z,i,k; long long sum; char ch; scanf("%d%d",&n,&q); memset(tree,0,sizeof(tree)); for(k=1;k<=n;k++) { scanf("%lld",&v[k]); } maketree(1,n,1); for(i=1;i<=q;i++) { scanf("%*c%c",&ch); if(ch==‘C‘) { scanf("%d%d%d",&x,&y,&z); add(x,y,z,1); } else if(ch==‘Q‘) { scanf("%d%d",&x,&y); sum=find(x,y,1); printf("%lld\n",sum); } } return 0; }
时间: 2024-10-12 11:06:46