【CODEVS1080】线段树练习
Description
一行N个方格,开始每个格子里都有一个整数。现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和;修改的规则是指定某一个格子x,加上或者减去一个特定的值A。现在要求你能对每个提问作出正确的回答。1≤N<100000,,提问和修改的总数m<10000条。
Input
输入文件第一行为一个整数N,接下来是n行n个整数,表示格子中原来的整数。接下一个正整数m,再接下来有m行,表示m个询问,第一个整数表示询问代号,询问代号1表示增加,后面的两个数x和A表示给位置X上的数值增加A,询问代号2表示区间求和,后面两个整数表示a和b,表示要求[a,b]之间的区间和。
Output
共m行,每个整数
Sample Input
6
4
5
6
2
1
3
4
1 3 5
2 1 4
1 1 9
2 2 6
Sample Output
22
22
HINT
1≤N≤100000, m≤10000 。
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int maxn=100010; 5 int tot=0; 6 int a[100005]; 7 struct treetype 8 { 9 int Left,Right; //区间[Left,Right) 10 int lptr,rptr; //左右孩子指针 11 int sum; //区间和 12 }t[2*maxn]; 13 void buildtree(int ll,int rr) //建树 14 { 15 int cur=++tot; //线段树中结点总个数 16 t[cur].Left=ll; 17 t[cur].Right=rr; 18 if(ll!=rr-1)//非单位区间 19 { 20 t[cur].lptr=tot+1; 21 buildtree(ll,(ll+rr)/2); 22 t[cur].rptr=tot+1; 23 buildtree((ll+rr)/2,rr); 24 t[cur].sum=t[t[cur].lptr].sum+t[t[cur].rptr].sum; 25 }else t[cur].sum=a[ll]; 26 } 27 void change(int k,int p,int delta) //修改单个元素的值,根节点作为第一个参数传入(k) 28 { 29 if(t[k].Left==t[k].Right-1) t[k].sum+=delta; 30 else 31 { 32 if (p<(t[k].Left+t[k].Right)/2) 33 change(t[k].lptr,p,delta); 34 if (p>=(t[k].Left+t[k].Right)/2) 35 change(t[k].rptr,p,delta); 36 t[k].sum=t[t[k].lptr].sum+t[t[k].rptr].sum; 37 } 38 } 39 int query(int k,int ll,int rr) //查询[ll,rr)区间和,根节点作为第一个参数传入(k) 40 { 41 if (ll<=t[k].Left&&rr>=t[k].Right) return t[k].sum; //区间覆盖树 42 int ans=0; 43 if (ll<(t[k].Left+t[k].Right)/2) ans+=query(t[k].lptr,ll,rr); 44 if (rr>(t[k].Left+t[k].Right)/2) ans+=query(t[k].rptr,ll,rr); 45 return ans; 46 } 47 int main() 48 { 49 int n; 50 scanf("%d",&n); 51 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 52 buildtree(1,n+1); 53 cin>>n; 54 int p,at,x; 55 for (int i=1;i<=n;i++) 56 { 57 cin>>at>>x>>p; 58 if (at==1) change(1,x,p); 59 if (at==2) printf("%d\n",query(1,x,p+1)); 60 } 61 return 0; 62 }