题意:
给定n个点n-1条边的树,第i条边为(ai,bi),
两种操作:
(1,e,x):假设删掉边e,删掉之后将第e条边ai连接的那块所有点的点权都加上x,
(2,e,x):假设删掉边e,删掉之后将第e条边bi连接的那块所有点的点权都加上x,
最后输出每个点的点权
数据范围:n,q<=2e5
解法:
令点1为根,dfs出每个点的深度d[],
对于每种操作,假设(x,y)要修改x连接的部分,
分两种情况:
1.如果d[x]>d[y],说明x在y的下面,那么需要将x子树上所有点加上x,
2.否则说明除了x子树,其他点都要加上x.
对于情况1:子树加法可以用树上差分,
对于情况2:除了子树,其他都加,可以转变为x子树减少x(也是树上差分),所有点增加x.
code:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxm=2e5+5;
vector<int>g[maxm];
int val[maxm];
int d[maxm];
int a[maxm];
int b[maxm];
int n,q;
void dfs(int x,int fa){
for(int v:g[x]){
if(v==fa)continue;
d[v]=d[x]+1;
dfs(v,x);
}
}
void dfs2(int x,int fa){
for(int v:g[x]){
if(v==fa)continue;
val[v]+=val[x];
dfs2(v,x);
}
}
signed main(){
ios::sync_with_stdio(0);
cin>>n;
for(int i=1;i<n;i++){
cin>>a[i]>>b[i];
g[a[i]].push_back(b[i]);
g[b[i]].push_back(a[i]);
}
dfs(1,1);
cin>>q;
int tot=0;
while(q--){
int t,e,x;cin>>t>>e>>x;
if(t==1){
//a
if(d[a[e]]>d[b[e]]){
val[a[e]]+=x;
}else{
val[b[e]]-=x;
tot+=x;
}
}else if(t==2){
//b
if(d[b[e]]>d[a[e]]){
val[b[e]]+=x;
}else{
val[a[e]]-=x;
tot+=x;
}
}
}
dfs2(1,1);
for(int i=1;i<=n;i++){
cout<<tot+val[i]<<endl;
}
return 0;
}