首先求出树的dfs序,对于第一种操作和第二种操作分开处理,第一种操作比较经典,就不说了。第二种操作其实和第一种也很类似,查询x点到根的权值和sum(x)=(disx+1)*v(x)-w,其中disx为x点到根的距离,v(x)表示以x到根之间的点为第二类操作的子树根所进行操作的权值和,这样相乘明显会有多余的部分,假设对y点进行第二类操作,使其和其子树上的点增加z,那么会多计算价值disy*z,使用两颗树状数组维护即可。
代码
1 #include<cstdio> 2 #define nc getchar 3 #define N 1000010 4 int tot,n,m,i,v[N],dp,p[N],pre[N],tt[N],L[N],R[N],a,b,T; 5 long long c[N][3],dis[N],ans; 6 inline int lowbit(int x) 7 { 8 return x&(-x); 9 } 10 void cc(int x,long long w,int typ) 11 { 12 while (x<=tot) 13 { 14 c[x][typ]+=w; 15 x+=lowbit(x); 16 } 17 } 18 long long sum(int x,int typ) 19 { 20 long long ans=0; 21 while (x) 22 { 23 ans+=c[x][typ]; 24 x-=lowbit(x); 25 } 26 return ans; 27 } 28 void link(int x,int y) 29 { 30 dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y; 31 } 32 void dfs(int x,int fa) 33 { 34 int i=p[x]; 35 tot++;L[x]=tot; 36 while (i) 37 { 38 if (tt[i]!=fa) 39 { 40 dis[tt[i]]=dis[x]+1; 41 dfs(tt[i],x); 42 } 43 i=pre[i]; 44 } 45 tot++;R[x]=tot; 46 } 47 int main() 48 { 49 scanf("%d%d",&n,&m); 50 for (i=1;i<=n;i++) 51 scanf("%d",&v[i]); 52 for (i=1;i<n;i++) 53 { 54 scanf("%d%d",&a,&b); 55 link(a,b);link(b,a); 56 } 57 dfs(1,0); 58 for (i=1;i<=n;i++) 59 { 60 cc(L[i],v[i],0); 61 cc(R[i],-v[i],0); 62 } 63 for (i=1;i<=m;i++) 64 { 65 scanf("%d",&T); 66 if (T==1) 67 { 68 scanf("%d%d",&a,&b); 69 cc(L[a],b,0); 70 cc(R[a],-b,0); 71 } 72 else 73 if (T==2) 74 { 75 scanf("%d%d",&a,&b); 76 cc(L[a],b,1); 77 cc(R[a],-b,1); 78 cc(L[a],dis[a]*(long long)b,2); 79 cc(R[a],-dis[a]*(long long)b,2); 80 } 81 else 82 { 83 scanf("%d",&a); 84 ans=sum(L[a],0)-sum(L[a],2)+sum(L[a],1)*(dis[a]+1); 85 printf("%lld ",ans); 86 } 87 } 88 89 }