线段树+差分——【模板】树状数组2
2017-10-13 19:34
375 查看
题目来源
洛谷P3368【模板】树状数组2 https://www.luogu.org/problem/show?pid=3368思路
按照差分思想 叶节点记录这个数与前一个数的差节点记录左右儿子(l,r)、区间范围(x,y)、区间和(num)
查询x时 递归查找1~x区间和即为数列中第x个数的值
修改x~y的节点加k时 将第x个点加k、第y+1个点减k(即加-k)即可
将第i个点n加v时 对由代表i~i区间的叶节点到根节点的路径上的节点的num进行修改
代码(C++)
#include <cstdio> using namespace std; int n,m,c,u,v,w; long long pre=0; struct tree { tree *l,*r; int x,y; long long num; }*root,*null=new tree(); tree* build(int st,int en); long long ask(int x,tree *pos); void change(int x,long long k,tree *pos); int main() { scanf("%d%d",&n,&m); root=build(1,n); for(int i=1;i<=m;++i) { scanf("%d",&c); if(c==1) { scanf("%d%d%lld",&u,&v,&w); change(u,w,root); if(v+1<=n) change(v+1,-w,root); } else { scanf("%d",&u); printf("%lld\n",ask(u,root)); } } return 0; } long long ask(int x,tree *pos) { if(x==pos->y) return pos->num; if(x>=pos->r->x) return ask(x,pos->r)+pos->l->num; else return ask(x,pos->l); } void change(int x,long long k,tree *pos) { if(pos->l==null&&pos->y==x) { pos->num+=k; return ; } if(x<=pos->l->y) change(x,k,pos->l); else change(x,k,pos->r); pos->num=pos->l->num+pos->r->num; return ; } tree* build(int st,int en) { tree *pos=new tree(); pos->x=st; pos->y=en; if(st==en) { pos->l=null; pos->r=null; scanf("%lld",&pos->num); pos->num-=pre; pre+=pos->num; } else { pos->l=build(st,(st+en)/2); pos->r=build((st+en)/2+1,en); pos->num=pos->l->num+pos->r->num; } return pos; }
相关文章推荐
- 树状数组 线段树 模板
- 个人模板 树状数组
- HDU 1166 敌兵布阵(树状数组模板)
- P3374 【模板】树状数组 1(单点增减,区间求和)
- 洛谷 P3374【模板】树状数组 1
- 树状数组模板
- 树状数组、线段树模板(一)——单点更新 + HDU 1166 敌兵布阵
- 树状数组模板
- 树状数组模板
- 树状数组基本模板
- Stars POJ2352(树状数组模板题)
- 树状数组(模板)
- 求逆序对模板题(完善模板:树状数组或归并排序)
- 【模板】逆序对(树状数组)
- 树状数组模板
- 敌兵布阵---hud1166(线段树或者树状数组模板)
- 树状数组模板(区间更新单点查询)
- 树状数组求逆序数的模板
- 二维树状数组模板
- 树状数组模板