洛谷 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 。
输入输出样例
输入样例#1:
复制
4 0 1 1 2 2 3 4 A 1 3 1 Q 0 Q 1 Q 2
输出样例#1: 复制
3 3 2
题解:
树链剖分的板子好久没打了,写一写。
代码:
// luogu-judger-enable-o2 // luogu-judger-enable-o2 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #define MAXN 400100 #define ll long long using namespace std; struct edge{ int first; int next; int to; }a[MAXN*2]; struct tree{ int l,r;ll sum,lz; }tr[MAXN*4]; int num,n; int dep[MAXN],sz[MAXN],id[MAXN],son[MAXN],tp[MAXN],dfn[MAXN],las[MAXN],fa[MAXN]; void addedge(int from,int to){ a[++num].to=to; a[num].next=a[from].first; a[from].first=num; } void dfs1(int now,int f){ fa[now]=f,sz[now]=1,dep[now]=dep[f]+1; for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to; if(to==f) continue; dfs1(to,now); sz[now]+=sz[to]; if(sz[son[now]]<sz[to]) son[now]=to; } } void dfs2(int now,int top){ dfn[now]=++num; tp[now]=top; if(son[now]) dfs2(son[now],top); for(int i=a[now].first;i;i=a[i].next){ int to=a[i].to;if(to==fa[now]||to==son[now]) continue; dfs2(to,to); } las[now]=num; } void pushdown(int xv){ int ls=2*xv,rs=2*xv+1; if(tr[xv].lz){ tr[ls].sum+=(tr[ls].r-tr[ls].l+1)*tr[xv].lz; tr[rs].sum+=(tr[rs].r-tr[rs].l+1)*tr[xv].lz; tr[ls].lz+=tr[xv].lz,tr[rs].lz+=tr[xv].lz; tr[xv].lz=0; } } void pushup(int xv){ tr[xv].sum=tr[xv*2].sum+tr[xv*2+1].sum; } void build(int xv,int l,int r){ if(l==r){ tr[xv].l=l,tr[xv].r=r,tr[xv].sum=0,tr[xv].lz=0; return; } tr[xv].l=l,tr[xv].r=r,tr[xv].sum=0,tr[xv].lz=0; int mid=(l+r)/2; build(xv*2,l,mid),build(xv*2+1,mid+1,r); } void modify(int xv,int l,int r,int z){ int L=tr[xv].l,R=tr[xv].r,mid=(L+R)/2; if(L==l&&R==r){ tr[xv].sum+=z*(R-L+1); tr[xv].lz+=z; return; } pushdown(xv); if(r<=mid) modify(xv*2,l,r,z); else if(l>mid) modify(xv*2+1,l,r,z); else modify(xv*2,l,mid,z),modify(xv*2+1,mid+1,r,z); pushup(xv); } ll query(int xv,int l,int r){ int L=tr[xv].l,R=tr[xv].r,mid=(L+R)/2; if(L==l&&R==r) return tr[xv].sum; pushdown(xv); if(r<=mid) return query(xv*2,l,r); else if(l>mid) return query(xv*2+1,l,r); else return query(xv*2,l,mid)+query(xv*2+1,mid+1,r); } void add(int x,int y,int z){ int topx=tp[x],topy=tp[y]; while(topx!=topy){ if(dep[topx]<dep[topy]) swap(x,y),swap(topx,topy); modify(1,dfn[topx],dfn[x],z); x=fa[topx];topx=tp[x]; } if(dep[x]<dep[y]) swap(x,y); modify(1,dfn[y],dfn[x],z); } int main() { scanf("%d",&n); for(int i=1;i<n;i++){ int x,y;scanf("%d%d",&x,&y); x++,y++; addedge(x,y),addedge(y,x); } dfs1(1,0);num=0; dfs2(1,1);fa[1]=1; build(1,1,n); int q;cin>>q; while(q--){ char id;cin>>id; if(id=='A'){ int x,y,z;scanf("%d%d%d",&x,&y,&z);x++,y++; add(x,y,z); } else{ int x;scanf("%d",&x);x++; printf("%lld\n",query(1,dfn[x],las[x])); } } return 0; }