[SHOI2012]魔法树
原题链接:https://www.luogu.org/problemnew/show/P3833
题目背景
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 。
输入输出样例
输入样例
4 0 1 1 2 2 3 4 A 1 3 1 Q 0 Q 1 Q 2
输出样例
3
3 2
树剖裸题.....记得开long long....
1 #include <cstdio> 2 #include <iostream> 3 #define ll long long 4 using namespace std; 5 const int N=1500000+10; 6 int v[N*2],nxt[N*2],first[N],cnt; 7 int pos[N],dep[N],fa[N],top[N],siz[N],son[N],sz; 8 int n,m; 9 struct seg{ 10 int l,r; 11 ll s,t; 12 }tr[N*4]; 13 14 void read(int &x){ 15 x=0;int f=1;char c=getchar(); 16 while(c<'0'||c>'9'){if(c=='-')f=-f;c=getchar();} 17 while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c-'0');c=getchar();} 18 x*=f; 19 } 20 21 void add(int a,int b){ 22 v[++cnt]=b; 23 nxt[cnt]=first[a]; 24 first[a]=cnt; 25 } 26 27 void dfs1(int x){ 28 siz[x]=1; 29 for(int i=first[x];i;i=nxt[i]){ 30 if(fa[x]==v[i]) continue; 31 dep[v[i]]=dep[x]+1; 32 fa[v[i]]=x; 33 dfs1(v[i]); 34 siz[x]+=siz[v[i]]; 35 if(siz[v[i]]>siz[son[x]]) son[x]=v[i]; 36 } 37 } 38 39 void dfs2(int x,int y){ 40 pos[x]=++sz;top[x]=y; 41 int k=son[x]; 42 if(!k) return ; 43 dfs2(k,y); 44 for(int i=first[x];i;i=nxt[i]) if(dep[v[i]]>dep[x]&&k!=v[i]) dfs2(v[i],v[i]); 45 } 46 47 void build(int k,int s,int t){ 48 tr[k].l=s;tr[k].r=t; 49 if(s==t) return ; 50 int mid=(s+t)/2; 51 build(k*2,s,mid);build(k*2+1,mid+1,t); 52 } 53 54 void push(int k){ 55 int x=tr[k].r-tr[k].l+1; 56 tr[k*2].t+=tr[k].t; 57 tr[k*2+1].t+=tr[k].t; 58 tr[k*2].s+=1ll*tr[k].t*(x-(x/2)); 59 tr[k*2+1].s+=1ll*tr[k].t*(x/2); 60 tr[k].t=0; 61 } 62 63 void ud(int k,int s,int t,ll v){ 64 int l=tr[k].l,r=tr[k].r; 65 if(s==l&&t==r){ 66 tr[k].t+=v; 67 tr[k].s+=1ll*v*(r-l+1); 68 return ; 69 } 70 if(tr[k].t) push(k); 71 int mid=(l+r)/2; 72 if(s>mid) ud(k*2+1,s,t,v); 73 else if(t<=mid) ud(k*2,s,t,v); 74 else { 75 ud(k*2,s,mid,v); 76 ud(k*2+1,mid+1,t,v); 77 } 78 tr[k].s=tr[k*2].s+tr[k*2+1].s; 79 } 80 81 void solud(int x,int y,ll v){ 82 while(top[x]!=top[y]){ 83 if(dep[top[x]]<dep[top[y]]) swap(x,y); 84 ud(1,pos[top[x]],pos[x],v); 85 x=fa[top[x]]; 86 } 87 if(pos[x]>pos[y]) swap(x,y); 88 ud(1,pos[x],pos[y],v); 89 } 90 91 ll qy(int k,int s,int t){ 92 int l=tr[k].l,r=tr[k].r; 93 if(s==l&&t==r) return tr[k].s; 94 if(tr[k].t) push(k); 95 int mid=(l+r)/2; 96 if(s>mid) return qy(k*2+1,s,t); 97 else if(t<=mid) return qy(k*2,s,t); 98 else return qy(k*2,s,mid)+qy(k*2+1,mid+1,t); 99 } 100 101 int main(){ 102 read(n); 103 for(int i=1;i<n;i++){ 104 int x,y; 105 read(x);read(y); 106 add(x+1,y+1);add(y+1,x+1); 107 } 108 dfs1(1);dfs2(1,1); 109 build(1,1,n); 110 int q;read(q); 111 for(int i=1;i<=q;i++){ 112 char c[10]; 113 int x,y; 114 ll z; 115 scanf("%s",c);read(x);++x; 116 if(c[0]=='Q') printf("%lld\n",qy(1,pos[x],pos[x]+siz[x]-1)); 117 else{ 118 read(y);scanf("%lld",&z);++y; 119 solud(x,y,z); 120 } 121 } 122 return 0; 123 }