题目:第一行输入数字n,第二行输入n个数字。第三行输入数字m,接下来输入m组数据(操作符p,数字x,数字y)。
其中p=1代表在x位置处+y,p=2对区间(x,y)求和并输出。
样例:
输入
6
4 5 6 2 1 3
4
1 3 5
2 1 4
1 1 9
2 2 6
输出
22
22
#include<cstdio> #include<iostream> using namespace std; int n,m,p,x,y,ans;//n->数据个数 ,m->修改+查询次数 ,p->操作类型,x,y->操作数,ans->求值 struct node { int l,r,w;//左右边界,权值 }tree[400001]; inline void build(int l,int r,int k)//内联函数,左边界=l,右边界=r,当前节点数=k,根节点序号为1 { tree[k].l=l;tree[k].r=r;//1,1,6 ||2,1,3 ||4,1,2|| 8,1,1||9,2,2||5,3,3||3,4,6||6,4,5||12,4,4||13,5,5||7,6,6(k,l,r) if(l==r) //l=r=1||l=r=2 ||l=r=3||l=r=4||l=r=5||l=r=6 { scanf("%d",&tree[k].w);//输入值tree[8].w=4 ||输入值 tree[9].w=5||输入值tree[5].w=6 ||tree[12].w=2||tree[13].w=1||tree[7].w=3 return ; } int m=(l+r)/2;//m为中点 //cout<<"建树过程"<< l<<m<<2*k<<endl; build(l,m,k*2);//建树(1,3,2) ||建树(1,2,4) ||建树(1,1,8) (此时 l=1,r=2,m=1) ||建树(4,5,6)||建树(4,4,12) //cout<<"建树过程"<< m+1<<r<<2*k+1<<endl; build(m+1,r,k*2+1);//树(1,1,8)已经建成返回,开始建树 (2,2,9) || 建树(3,3,5)||建树(4,6,3) ||建树(5,5,13)||建树(6,6,7) tree[k].w=tree[k*2].w+tree[k*2+1].w;//tree[4].w= 4+5=9||tree[2].w=9+6=15||tree[6].w=2+1=3||tree[3].w=3+3=6||tree[1].w=15+6=21 } inline void add(int k)//k=1,(x=3,y=5) { if(tree[k].l==tree[k].r)//找到该位置 { tree[k].w+=y; return; } int m=(tree[k].l+tree[k].r)/2; if(x<=m) add(k*2);//x在左树 else add(k*2+1); tree[k].w=tree[k*2].w+tree[k*2+1].w; } inline void sum(int k) { if(tree[k].l>=x&&tree[k].r<=y) { ans+=tree[k].w; return; } int m=(tree[k].l+tree[k].r)/2; if(x<=m) sum(k*2); if(y>m) sum(k*2+1); } int main() { scanf("%d",&n);//输入n个数 build(1,n,1);// 建立线段树 scanf("%d",&m);//输入操作次数 for(int i=1;i<=m;i++) { scanf("%d%d%d",&p,&x,&y); ans=0; if(p==1) add(1); else { sum(1); printf("%d\n",ans); } } }
ps:线段树结构的三个元素为左右边界和权值,真正的数据存储在结点(即左右边界相等的地方),(本题中)其他结点权值存储的是左右孩子的和。从1开始进行双递归建树
l==r时为输入结点也是递归出口。查询和操作时也是从1开始条件递归操作,注意找到递归出口。