单点更新
#include <iostream> using namespace std; int tree[10000]; void buildtree(int arr[],int tree[],int node,int start,int end) { if(start==end) { tree[node]=arr[end]; return ; } int left_node=node*2+1; int right_node=node*2+2; int mid=(start+end)/2; buildtree(arr,tree,left_node,start,mid); buildtree(arr,tree,right_node,mid+1,end); tree[node]=tree[left_node]+tree[right_node]; } void update(int arr[],int tree[],int node,int start,int end,int idx,int val) { if(start==end) { arr[start]=val; tree[node]=val; return; } int left_node=node*2+1; int right_node=node*2+2; int mid=(start+end)/2; if(idx>=start&&idx<=mid) { update(arr,tree,left_node,start,mid,idx,val); } else { update(arr,tree,left_node,mid+1,end,idx,val); } tree[node]=tree[left_node]+tree[right_node]; } int query(int arr[],int tree[],int node,int start,int end,int L,int R) { cout<<"left = "<<start<<endl; cout<<"right = "<<end<<endl; cout<<endl; if(R<start||L>end) { return 0; } if (start==end||(L<=start&&R>=end)) { return tree[node]; } int left_node=node*2+1; int right_node=node*2+2; int mid=(start+end)/2; int left_sum=query(arr,tree,left_node,start,mid,L,R); int right_sum=query(arr,tree,right_node,mid+1,end,L,R); return left_sum+right_sum; } int main() { int arr[]= {1,2,3,4,5,6,7,8,9,10}; int size=sizeof(arr)/sizeof(int); buildtree(arr,tree,0,0,size-1); update(arr,tree,0,0,size-1,0,2); for(int i=0; i<10; i++) cout<<arr[i]<<endl; cout<<query(arr,tree,0,0,size-1,6,size-1); }
区间更新//POJ 3468 A Simple Problem with Integers(线段树区间求和)
#include <iostream> #include <cstdio> #define N 100004 using namespace std; typedef long long ll; typedef struct anode { ll lazy,sum; int l,r; } node; int arr[N]; node tree[4*N]; ll sum; void buildtree(int p,int start,int end)//建立线段树 { tree[p].l=start; tree[p].r=end; if(start ==end) { tree[p].sum=arr[end]; return ; } int left_node=p*2+1; int right_node=p*2+2; int mid=(start + end )/2; buildtree(left_node,start,mid);//建立左右子树 buildtree(right_node,mid+1,end); tree[p].sum=tree[left_node].sum+tree[right_node].sum;//回溯计算值 } void pushDown(int p)//lazy标记下放 { int mid=(tree[p].l+tree[p].r)/2; int left_node=2*p+1; int right_node=2*p+2; ll lazy=tree[p].lazy; tree[left_node].sum+=(mid-tree[p].l+1)*lazy;// tree[right_node].sum+=(tree[p].r-mid)*lazy; tree[left_node].lazy+=lazy; //加lazy标记 tree[right_node].lazy+=lazy; tree[p].lazy=0;//分配完成,释放lazy标记 } void updata(int p,int start,int end,int x)//区间更新 { if(start<=tree[p].l&&end>=tree[p].r) { tree[p].sum+=(tree[p].r-tree[p].l+1)*x; tree[p].lazy+=x; return; }//lazy延迟,sum累加 if(tree[p].lazy) pushDown(p);//lazy下放,不然 pushup 不真实是没加的数据,会出错 int left_node=2*p+1; int right_node=2*p+2; int mid=(tree[p].l+tree[p].r)/2; if(start>mid) { updata(right_node,start,end,x); } else if(end<=mid) { updata(left_node,start,end,x); } else { updata(right_node,start,end,x); updata(left_node,start,end,x); } tree[p].sum=tree[left_node].sum+tree[right_node].sum; } void query(int p,int start,int end)//查询 { if((tree[p].l>=start&&tree[p].r<=end)) { sum+=tree[p].sum; return ; }//直接加,因为lazy 标记对下方节点生效,对自生无影响 if(tree[p].l>end||tree[p].r<start) { return; }//剪枝 if(tree[p].lazy) pushDown(p);//lazy标记下放 int left_node=2*p+1; int right_node=2*p+2; int mid=(tree[p].l+tree[p].r)/2; if(start>mid)//三种情况,1 在mid 左边,2在mid 右边 ,3横跨mid { query(right_node,start,end); } else if(end<=mid) { query(left_node,start,end); } else { query(right_node,start,end); query(left_node,start,end); } } int main() { int n,m,l,r,x;char c[2]; cin>>n>>m; for(int i=0;i<n;i++) scanf("%d",&arr[i]); buildtree(0,0,n-1); while(m--){ scanf("%s%d%d",c,&l,&r); if(c[0]=='Q'){ sum=0; query(0,l-1,r-1); printf("%lld\n",sum); } else{ scanf("%d",&x); updata(0,l-1,r-1,x); } } }