线段树是连续区间动态更新的有力工具,由二叉树的特性可知其操作复杂度为 log(N)
本题是最最基础的线段树,但由此也算是入门了
线段树学习推荐优秀博客:点击打开链接
/* *********************************************** Author :angon Created Time :2016/3/27 20:00:05 File Name : ************************************************ */ #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <set> #include <map> #include <string> #include <math.h> #include <stdlib.h> #include <time.h> using namespace std; const int maxn=50005; int a[maxn]; struct node { int left,right; int value; }; node segTree[4*maxn]; void build(int i,int l,int r) { segTree[i].left=l; segTree[i].right=r; if(l==r) { segTree[i].value=a[l]; return ; } //递归构造左右子树 build(i<<1,l,(l+r)>>1); build(i<<1|1,((l+r)>>1)+1,r); // |1相当于+1 segTree[i].value=segTree[i<<1].value+segTree[i<<1|1].value; //回溯时更新节点信息(由下至上) } void add(int i,int x,int y) //单点更新信息,将y加到a[x]上,并更新被其影响的节点的值 { if(segTree[i].left==segTree[i].right && segTree[i].left==x) //找到所更新的节点 { segTree[i].value+=y; return ; } int mid=(segTree[i].left+segTree[i].right)>>1; if(x<=mid) add(i<<1,x,y); else add(i<<1|1,x,y); segTree[i].value=segTree[i<<1].value + segTree[i<<1|1].value; //回溯时更新节点信息 } int ans; void query(int i,int l,int r) //查询信息,l,r为所有查询的区间 { if(segTree[i].left==l && segTree[i].right==r) //找到一次完全重合的区间 { ans+=segTree[i].value; return ; } //递归齐左右孩子 i<<=1; if(l<=segTree[i].right) //如果区间涉及左孩子,递归左孩子,下同 query(i,l,min(segTree[i].right,r)); i++; if(r>=segTree[i].left) query(i,max(l,segTree[i].left),r); } int main() { int T,n,ca=0; scanf("%d",&T); while(T--) { printf("Case %d:\n",++ca); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); char s[6]; while(scanf("%s",s)) { if(s[0]=='E') break; int x,y; scanf("%d%d",&x,&y); if(s[0]=='A') add(1,x,y); else if(s[0]=='S') add(1,x,-y); else if(s[0]=='Q') { ans=0; query(1,x,y); printf("%d\n",ans); } } } return 0; }