线段树模板
2017-09-02 17:36
351 查看
今天看了半天,主要是知识点,还看了些博客,最后总结出来线段树的这么一套模板,连带着自己加的些理解注释,模板库终于不是空的了。
!!!补!!!后来用模板超时,发现错误点,应该在查询时加上一步判断——是否 tree[].r<left || tree[].l>right,是则return 。(已在代码中加上)。
!!!补!!!后来用模板超时,发现错误点,应该在查询时加上一步判断——是否 tree[].r<left || tree[].l>right,是则return 。(已在代码中加上)。
#include<iostream> using namespace std; const int MAX=10010; int N,M,ans; int a[MAX]; struct node { int l,r; int sum; int f; }tree[MAX*4+1]; inline void build(int k,int left,int right)//建树 { tree[k].l=left; tree[k].r=right; if(tree[k].l==tree[k].r)//如果是子节点 { tree[k].sum=a[left]; return ; } int mid=(left+right)/2; build(k*2,left,mid);//左子树 build(k*2+1,mid+1,right);//右子树 tree[k].sum=tree[k*2].sum+tree[k*2+1].sum;//回溯 修改当前 } inline void down(int k)//标记下传 { tree[k*2].f+=tree[k].f;//传向左右子树 tree[k*2+1].f+=tree[k].f; tree[k*2].sum+=tree[k].f*(tree[k*2].r-tree[k*2].l+1); tree[k*2+1].sum+=tree[k].f*(tree[k*2+1].r-tree[k*2+1].l+1); tree[k].f=0;//本身设为 0 } inline void queryPoint(int k,int pos)//单点查询 {//k是当前节点 pos是要查询数组位置 if(tree[k].l==tree[k].r) { ans=tree[k].sum; return ; } if(tree[k].f)//如果有标记 下传 down(k); int mid=(tree[k].l+tree[k].r)/2; if(pos<=mid) queryPoint(k*2,pos); else queryPoint(k*2+1,pos); } inline void changePoint(int k,int pos,int d)//单点修改 {//k是当前位置 pos是数组中位置 d是要求改成的数 if(tree[k].l==tree[k].r) { tree[k].sum+=d;//不是修改 是 +d return; } if(tree[k].f)//下传 down(k); int mid=(tree[k].l+tree[k].r)/2; if(pos<=mid) changePoint(k*2,pos,d); else changePoint(k*2+1,pos,d); tree[k].sum=tree[k*2].sum+tree[k*2+1].sum; } inline void queryInterval(int k,int left,int right)//区间查询 { if(tree[k].r<left || tree[k].l>right)//后来补错加上的,否则超时 return ; if(tree[k].l>=left && tree[k].r<=right) {//当节点k的(l,r)在【left,right】中间时 ans+ ans+=tree[k].sum; return; } if(tree[k].f)//下传 down(k); int mid=(tree[k].l+tree[k].r)/2; if(left<=mid) queryInterval(k*2,left,right); if(right>mid) queryInterval(k*2+1,left,right); } inline void changeInterval(int k,int left,int right,int d)//区间修改 { if(tree[k].l>=left && tree[k].r<=right)//节点k完全被包含时 { tree[k].sum+=(tree[k].r-tree[k].l+1)*d; tree[k].f+=d;//不是修改 是 +d return; } if(tree[k].f) down(k); int mid=(tree[k].l+tree[k].r)/2; if(left<=mid) changeInterval(k*2,left,right,d); if(right>mid) changeInterval(k*2+1,left,right,d); tree[k].sum=tree[k*2].sum+tree[k*2+1].sum;//回溯 } int main() { int p,x,l,r,d; cin>>N;//n个节点 for(int i=1; i<=N; i++) cin>>a[i]; build(1,1,N);//建树 cout<<"建树ok"<<endl; cin>>M;//m种操作 for(int i=1;i<=M;i++) { cout<<"选择操作:"<<endl; cin>>p; ans=0; if(p==1) { cin>>x; queryPoint(1,x);//单点查询,输出第x个数 cout<<ans<<endl;; } else if(p==2) { cin>>x>>d; changePoint(1,x,d);//单点修改 } else if(p==3) { cin>>l>>r; queryInterval(1,l,r);//区间查询 cout<<ans<<endl; } else { cin>>l>>r>>d; changeInterval(1,l,r,d); } } return 0; }
相关文章推荐
- HDU 1754 B I Hate It 线段树 单点更新 区间最大值 模板
- 模板线段树1
- 线段树模板
- HDU(1166),线段树模板,单点更新,区间总和
- 线段树模板
- 郁闷的出纳员 (splay的区间标记模板,删除区间,add标记,类似线段树)
- poj3468(线段树区间更新&区间求和模板)
- 线段树模板(单点更新和区间更新)
- BZOJ-1036 树的统计Count 链剖线段树(模板)=(树链剖分+线段树)
- 【模板】线段树 2
- 线段树模板-成段替换
- 线段树模板
- 主席树练习1——P3834 【模板】可持久化线段树 1(主席树)
- 【Splay】洛谷3372 【模板】线段树 1
- hdoj 敌兵布阵 1166 (线段树 模板)
- 线段树维护区间最大模板(单结点更新)(1754)
- HDOJ 5217 Brackets(zkw线段树模板+单点更新)
- Poj 3667 线段树区间合并 (模板)
- 线段树:CDOJ1591-An easy problem A (RMQ算法和最简单的线段树模板)
- 线段树大模板(区间更新,单点更新,查询区间最值等等)