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
//裸树剖 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1e5+5; inline int read() { char c=getchar();int num=0,f=1; for(;!isdigit(c);c=getchar()) f=c=='-'?-1:f; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num*f; } int n,q; int head[N],num_edge; struct Edge { int v,nxt; }edge[N]; struct NODE { int son,fa; int s,t; int dep,siz; int top; }node[N]; struct TREE { TREE *lson,*rson; int l,r,mid,len; long long sum,lazy; }tree[N<<2]; typedef TREE* Tree; Tree now_node; inline void add_edge(int u,int v) { edge[++num_edge].v=v; edge[num_edge].nxt=head[u]; head[u]=num_edge; } void dfs1(int u) { node[u].siz=1; for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; node[v].fa=u; node[v].dep=node[u].dep+1; dfs1(v); node[u].siz+=node[v].siz; if(node[u].son==0||node[v].siz>node[node[u].son].siz) node[u].son=v; } } int bound; void dfs2(int u,int top) { node[u].s=++bound; node[u].top=top; if(node[u].son) { dfs2(node[u].son,top); for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(v==node[u].son) continue; dfs2(v,v); } } node[u].t=bound; } Tree Root; void build(Tree &root,int l,int r) { root=++now_node; root->l=l,root->r=r,root->mid=l+r>>1,root->len=r-l+1; if(l==r) { // root->lson=tree, // root->rson=tree; return; } build(root->lson,l,root->mid); build(root->rson,root->mid+1,r); } inline void pushdown(Tree root) { if(!(root->lazy)) return; root->lson->lazy+=root->lazy; root->rson->lazy+=root->lazy; root->lson->sum+=root->lson->len*root->lazy; root->rson->sum+=root->rson->len*root->lazy; root->lazy=0; } void modify(Tree root,int l,int r,int val) { if(root->l==l&&root->r==r) { root->sum+=val*root->len; root->lazy+=val; return; } pushdown(root); if(r<=root->mid) modify(root->lson,l,r,val); else if(l>root->mid) modify(root->rson,l,r,val); else { modify(root->lson,l,root->mid,val); modify(root->rson,root->mid+1,r,val); } root->sum=root->lson->sum+root->rson->sum; } long long query(Tree root,int l,int r) { if(root->l==l&&root->r==r) return root->sum; pushdown(root); if(r<=root->mid) return query(root->lson,l,r); else if(l>root->mid) return query(root->rson,l,r); else return query(root->lson,l,root->mid)+query(root->rson,root->mid+1,r); } void Modify(int x,int y,int val) { int fx=node[x].top,fy=node[y].top; while(fx!=fy) { if(node[fx].dep>node[fy].dep) { modify(Root,node[fx].s,node[x].s,val); x=node[fx].fa, fx=node[x].top; } else { modify(Root,node[fy].s,node[y].s,val); y=node[fy].fa, fy=node[y].top; } } if(node[x].dep>node[y].dep) modify(Root,node[y].s,node[x].s,val); else modify(Root,node[x].s,node[y].s,val); } char s[5]; int main() { now_node=tree; n=read(); for(int i=1,a,b;i<n;++i) { a=read(),b=read(); add_edge(a,b); } dfs1(0); dfs2(0,0); build(Root,1,n); q=read(); for(int i=1,a,b,c;i<=q;++i) { scanf("%s",s); if(s[0]=='A') { a=read(),b=read(),c=read(); Modify(a,b,c); } else { a=read(); printf("%lld\n",query(Root,node[a].s,node[a].t)); } } return 0; }