P3833 [SHOI2012]魔法树
题目背景
SHOI2012 D2T3
题目描述
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 。
输入输出样例
树链剖分模板题,注意一下细节即可
#include<bits/stdc++.h> #define N 1010100 #define LL long long using namespace std; struct node { LL to,next; } e[N]; struct tree { LL l,r,w,f; } tr[N]; LL n,m,head[N],tot,ans; //(u,v)树上修改 //询问子树大小 void add(LL u,LL v) { e[++tot].to=v,e[tot].next=head[u],head[u]=tot; } LL dep[N],siz[N],son[N],fa[N]; void dfs(LL u,LL f,LL deep) { dep[u]=deep,siz[u]=1,fa[u]=f; LL maxson=-1; for(LL i=head[u]; i; i=e[i].next) { LL v=e[i].to; if(v==f) continue; dfs(v,u,deep+1); siz[u]+=siz[v]; if(siz[v]>maxson) maxson=siz[v],son[u]=v; } } LL top[N],id[N],item; void dfs2(LL u,LL topf) { id[u]=++item,top[u]=topf; if(!son[u]) return; dfs2(son[u],topf); for(LL i=head[u]; i; i=e[i].next) { LL v=e[i].to; if(v==fa[u]||v==son[u]) continue; dfs2(v,v); } } void build(LL k,LL l,LL r) { tr[k].l=l,tr[k].r=r; if(l==r) return; LL mid=(l+r)/2; build(k*2,l,mid); build(k*2+1,mid+1,r); } void upda(LL k) { tr[k].w=tr[k*2].w+tr[k*2+1].w; } void down(LL k) { LL f=tr[k].f; tr[k].f=0; tr[k*2].w=(tr[k*2].w+f*(tr[k*2].r-tr[k*2].l+1)); tr[k*2+1].w=(tr[k*2+1].w+f*(tr[k*2+1].r-tr[k*2+1].l+1)); tr[k*2].f+=f,tr[k*2+1].f+=f; } void change_LLerval(LL k,LL l,LL r,LL p) { LL ll=tr[k].l,rr=tr[k].r,mid=(ll+rr)/2; if(ll>=l&&rr<=r) { tr[k].w=(tr[k].w+(rr-ll+1)*p); tr[k].f+=p; return; } if(tr[k].f) down(k); if(l<=mid) change_LLerval(k*2,l,r,p); if(r>mid) change_LLerval(k*2+1,l,r,p); upda(k); } void ask_LLerval(LL k,LL l,LL r) { LL ll=tr[k].l,rr=tr[k].r,mid=(ll+rr)/2; if(ll>=l&&rr<=r) { ans+=tr[k].w; return; } if(tr[k].f) down(k); if(l<=mid) ask_LLerval(k*2,l,r); if(r>mid) ask_LLerval(k*2+1,l,r); upda(k); } void change(LL a,LL b,LL p) { while(top[a]!=top[b]) { if(dep[top[a]]<dep[top[b]]) swap(a,b); change_LLerval(1,id[top[a]],id[a],p); a=fa[top[a]]; } if(dep[a]<dep[b]) swap(a,b); change_LLerval(1,id[b],id[a],p); } LL sum(LL a) { ans=0; ask_LLerval(1,id[a],id[a]+siz[a]-1); return ans; } int main() { scanf("%lld",&n); for(LL a,b,i=1; i<n; i++) { scanf("%lld%lld",&a,&b); add(a+1,b+1); } dfs(1,0,1); dfs2(1,1); build(1,1,n); scanf("%lld",&m); for(LL a,b,c,i=1; i<=m; i++) { char x; cin>>x; if(x=='A') { scanf("%lld%lld%lld",&a,&b,&c); change(a+1,b+1,c); } else { scanf("%lld",&a); printf("%lld ",sum(a+1)); } } return 0; }