[线段树] (a) hdu1166 敌兵布阵单点修改区间求和
如在阅读本文时遇到不懂的部分,请在评论区询问,或跳转 线段树总介绍
本题考查区间维护:单点修改、区间求和。
那么显然是线段树,最基础的类型。
更新函数
1. 对于一般的单点更新函数,递归地找出点的位置,每次判断在左儿子还是右儿子,最后更新完要回溯pushup。
2. 由于本题是单点修改,也可以采取从下往上修改的方式,即先找到该点,再依次找其父亲直至根节点,每个点pushup,但此时在建树时要记录每个值所对应的点(此点 l==r)。
3. 由于本题是单点修改,也可以把pushup写成 sum[root]+=dalta,因为此区间下一定只有一个点发生改变,故总值也只改变一倍。
4. 区间更新代码(中式英文请见谅)
void update_common(int rt,int x,int delta){ if(x==t[rt].l&&x==t[rt].r){t[rt].v+=delta;return;} if(x<=mid)update_common(ls,x,delta); else update_common(rs,x,delta); pushup(rt);return; } void update_not_common(int x,int delta){ int rt=pos[x]; //Attention!Don't write "..+=delta" again for the "pos" node while(rt!=1){t[rt].v+=delta;rt>>=1;} //Add for the nodes in this road (without pushup) return; }
询问函数
好普通啊....过水不予讲解
int query(int rt,int x,int y){ if(x<=t[rt].l&&y>=t[rt].r)return t[rt].v; int res=0; if(x<=mid)res+=query(ls,x,y); if(y>mid)res+=query(rs,x,y); return res; }
总代码
/*hdu1166 两种update均可AC*/ #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=1e7+3; int T,n,a[N],pos[N]; struct node{int l,r,v;}t[N<<2]; string order; #define mid (t[rt].l+t[rt].r>>1) #define ls (rt<<1) #define rs (ls|1) #define pushup(rt) t[rt].v=t[ls].v+t[rs].v void build(int rt,int l,int r){ t[rt].l=l,t[rt].r=r,t[rt].v=0; if(l==r){ t[rt].v=a[l]; pos[l]=rt; return;} build(ls,l,mid);build(rs,mid+1,r); pushup(rt);return; } void update_common(int rt,int x,int delta){ if(x==t[rt].l&&x==t[rt].r){t[rt].v+=delta;return;} if(x<=mid)update_common(ls,x,delta); else update_common(rs,x,delta); pushup(rt);return; } void update_not_common(int x,int delta){ int rt=pos[x]; //Attention!Don't write "..+=delta" again for the "pos" node while(rt!=1){t[rt].v+=delta;rt>>=1;} //Add for the nodes in this road (without pushup) return; } int query(int rt,int x,int y){ if(x<=t[rt].l&&y>=t[rt].r)return t[rt].v; int res=0; if(x<=mid)res+=query(ls,x,y); if(y>mid)res+=query(rs,x,y); return res; } int main() { //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); scanf("%d",&T); register int x,y,Case=0; while(T--){ printf("Case %d:\n",++Case); scanf("%d",&n); //ini(); for(register int i=1;i<=n;++i)scanf("%d",&a[i]); build(1,1,n); while(cin>>order&&order!="End"){ scanf("%d%d",&x,&y); if(order=="Add") //update_common(1,x,y); update_not_common(x,y); else if(order=="Sub") //update_common(1,x,-y); update_not_common(x,-y); else printf("%d\n",query(1,x,y)); } } return 0; }
End