[SHOI2012]魔法树
题目描述
Harry Potter 新学了一种魔法:可以让改变树上的果子个数。满心欢喜的他找到了一个巨大的果树,来试验他的新法术。
这棵果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u],保证有fa[u] < u。初始时,这棵果树上的果子都被 Dumbledore 用魔法清除掉了,所以这个果树的每个节点上都没有果子(即0个果子)。
不幸的是,Harry 的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry 的魔法可以这样描述:
Add u v d
表示将点u和v之间的路径上的所有节点的果子个数都加上d。
接下来,为了方便检验 Harry 的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:
Query u
表示当前果树中,以点u为根的子树中,总共有多少个果子?
输入输出格式
输入格式:
第一行一个正整数N (1 ≤ N ≤ 100000),表示果树的节点总数,节点以0,1,…,N − 1标号,0一定代表根节点。
接下来N − 1行,每行两个整数a,b (0 ≤ a < b < N),表示a是b的父亲。
接下来是一个正整数Q(1 ≤ ? ≤ 100000),表示共有Q次操作。
后面跟着Q行,每行是以下两种中的一种:
A u v d,表示将u到v的路径上的所有节点的果子数加上d;0 ≤ u,v <N,0 < d < 100000
Q u,表示询问以u为根的子树中的总果子数,注意是包括u本身的。
输出格式:
对于所有的Query操作,依次输出询问的答案,每行一个。答案可能会超过2^32 ,但不会超过10^15 。
输入输出样例
输入样例#1:
4 0 1 1 2 2 3 4 A 1 3 1
Q 0 Q 1 Q 2
输出样例#1:
3 3 2
solution:
又是一道树链剖分,又是一道模板题。
不会树链剖分的戳这里 树链剖分
因为一棵子树在这个线段树上是连续的,所以第二个操作就迎刃而解了,直接在线段树上查询。至于第一个操作,就先让u,v跳到一条链上,在链上编号连续,所以对于同一链上的可以用线段树维护。
ADD 操作 就是这样的。
inline void change(int x,int y,int z) { int tx=top[x],ty=top[y]; while(tx!=ty){ if(dep[tx]>dep[ty]) { swap(x,y); swap(tx,ty); } update(1,num[ty],num[y],z); y=fa[ty];ty=top[y]; } if(x==y){ update(1,num[x],num[x],z); } else{ if(dep[x]>dep[y]) swap(x,y); update(1,num[x],num[y],z); } }
线段树:区间修改
inline void update(int o,int x,int y,int k) { int l=tree[o].l; int r=tree[o].r; if(l>=x&&r<=y) { tree[o].sum+=(r-l+1)*k; add[o]+=k; return; } if(x>r||l>y) return; else { if(add[o]) pushup(o); update(lc,x,y,k); update(rc,x,y,k); tree[o].sum=tree[lc].sum+tree[rc].sum; } }
线段树:区间查询
inline long long query(int o,int x,int y) { int l=tree[o].l; int r=tree[o].r; if(l>=x&&r<=y) { return tree[o].sum; } if(x>r||l>y) return 0; else { if(add[o]) pushup(o); return query(lc,x,y)+query(rc,x,y); } }
下放标记及建树
inline void build(int o,int l,int r) { tree[o].l=l; tree[o].r=r; if(l==r){ tree[o].sum=0; return; } else { int mid = tree[o].mid(); build(lc,l,mid); build(rc,mid+1,r); tree[o].sum=tree[lc].sum+tree[rc].sum; } } inline void pushup(int o) { add[lc]+=add[o]; add[rc]+=add[o]; tree[lc].sum+=(tree[lc].r-tree[lc].l+1)*add[o]; tree[rc].sum+=(tree[rc].r-tree[rc].l+1)*add[o]; add[o]=0; }
完整代码
#include<bits/stdc++.h> using namespace std; const int MAXN = 100000 + 10; inline int read() { char ch; int fl=1; int xx=0; do{ ch= getchar(); if(ch=='-') fl=-1; }while(ch<'0'||ch>'9'); do{ xx=(xx<<3)+(xx<<1)+ch-'0'; ch=getchar(); }while(ch>='0'&&ch<='9'); return xx*fl; } int n,q; struct node { int to; int next; };node g[MAXN*2]; int cnt=0,head[MAXN]; inline void addedge(int a,int b) { ++cnt;g[cnt].to=b;g[cnt].next=head[a];head[a]=cnt;return; } int fa[MAXN],dep[MAXN],son[MAXN],tot[MAXN]; #define v g[i].to inline void dfs(int now) { son[now]=0,tot[now]=1; for(int i=head[now];i>0;i=g[i].next){ if(v!=fa[now]){ fa[v]=now; dep[v]=dep[now]+1; dfs(v); if(tot[son[now]]<tot[v]) son[now]=v; tot[now]+=tot[v]; } } } int num[MAXN],top[MAXN],h=0; inline void dfs2(int now,int t) { top[now]=t;++h;num[now]=h; if(son[now]!=0) dfs2(son[now],t); for(int i=head[now];i>0;i=g[i].next) { if(v!=fa[now]&&v!=son[now]) dfs2(v,v); } } struct s_tree { int l; int r; long long sum; inline int mid() { return (l+r)>>1; } };s_tree tree[MAXN*4]; long long add[MAXN*4]; #define lc o<<1 #define rc o<<1|1 inline void build(int o,int l,int r) { tree[o].l=l; tree[o].r=r; if(l==r){ tree[o].sum=0; return; } else { int mid = tree[o].mid(); build(lc,l,mid); build(rc,mid+1,r); tree[o].sum=tree[lc].sum+tree[rc].sum; } } inline void pushup(int o) { add[lc]+=add[o]; add[rc]+=add[o]; tree[lc].sum+=(tree[lc].r-tree[lc].l+1)*add[o]; tree[rc].sum+=(tree[rc].r-tree[rc].l+1)*add[o]; add[o]=0; } inline void update(int o,int x,int y,int k) { int l=tree[o].l; int r=tree[o].r; if(l>=x&&r<=y) { tree[o].sum+=(r-l+1)*k; add[o]+=k; return; } if(x>r||l>y) return; else { if(add[o]) pushup(o); update(lc,x,y,k); update(rc,x,y,k); tree[o].sum=tree[lc].sum+tree[rc].sum; } } inline void change(int x,int y,int z) { int tx=top[x],ty=top[y]; while(tx!=ty){ if(dep[tx]>dep[ty]) { swap(x,y); swap(tx,ty); } update(1,num[ty],num[y],z); y=fa[ty];ty=top[y]; } if(x==y){ update(1,num[x],num[x],z); } else{ if(dep[x]>dep[y]) swap(x,y); update(1,num[x],num[y],z); } } inline long long query(int o,int x,int y) { int l=tree[o].l; int r=tree[o].r; if(l>=x&&r<=y) { return tree[o].sum; } if(x>r||l>y) return 0; else { if(add[o]) pushup(o); return query(lc,x,y)+query(rc,x,y); } } int main() { n=read(); for(int i=1;i<=n;i++) { head[i]=-1; } for(int i=1;i<n;i++) { int x=read(),y=read(); x++; y++; addedge(x,y); addedge(y,x); } fa[1]=0;dep[1]=1; dfs(1); dfs2(1,1); build(1,1,h); q=read(); for(int i=1;i<=q;i++) { char op; int x,y,z; scanf("%s",&op); if(op=='A') { x=read(),y=read(),z=read(); x++; y++; change(x,y,z); } else { x=read(); x++; printf("%lld\n",query(1,num[x],num[x]+tot[x]-1)); } } }