ABC187 E - Through Path(树上差分)

题意:

在这里插入图片描述
给定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;
}

猜你喜欢

转载自blog.csdn.net/weixin_44178736/article/details/112692509