【树上模拟】

【树上模拟】

1-1-1, Free Tree!

https://codeforces.com/contest/2126/problem/F
很关键的一个优化点:父亲有且只有一个
->将遍历出边O(n)优化到:遍历父亲O(1)/儿子(如果可以一起维护)

题目大意

image

思路

难点在于每次修改颜色之后需要遍历所有出边的点来修改
->如果变成只修改父亲呢?

代码

const int N=2e5+10;
int n,q; 
vector<PII> g[N];
map<int,i64> p[N];//颜色,花销
int a[N];
int fa[N];
void init(int x){
    for(int i=1;i<=x;i++){
        for(auto &[key,val]:p[i]){
            val=0;
        }
        p[i].clear();
        g[i].clear();
        a[i]=0;
        fa[i]=i;
    }
}
//对于一个点,他的所有子节点我可以直接维护 父节点单独判断
void dfs(int u,int f){
    fa[u]=f;
    for(auto son:g[u]){
        int pos=son.fi;
        i64 val=son.sc;
        if(pos!=f){
            p[u][a[pos]]+=val;
            dfs(pos,u);
        }
    }
}
void solve(){
    cin>>n>>q;
    init(n);
    for(int i=1;i<=n;i++) cin>>a[i];
    i64 ans=0;
    map<pair<int,int>,i64> bian;
    for(int i=1;i<n;i++){
        int u=0,v=0;
        i64 c=0;
        cin>>u>>v;
        cin>>c;
        if(a[u]!=a[v]) ans+=c;
        g[u].push_back({v,c});
        g[v].push_back({u,c});
        if(u>v) swap(u,v);
        bian[{u,v}]=c;
    }
    dfs(1,0);
    while(q--){
        int v,x;
        cin>>v>>x;
        if(a[v]==x){
            cout<<ans<<endl;
            continue;
        }
        //非叶节点
        if(v!=1){
            if(x==a[fa[v]] && a[v]!=a[fa[v]]){
            	ans-=bian[{min(v,fa[v]),max(v,fa[v])}];
            }
            else if(a[v]==a[fa[v]] && x!=a[fa[v]]){
            	ans+=bian[{min(v,fa[v]),max(v,fa[v])}];
            }
        }
        ans+=p[v][a[v]];
        ans-=p[v][x];
        if(v!=1){
            p[fa[v]][a[v]]-=bian[{min(v,fa[v]),max(v,fa[v])}];
            p[fa[v]][x]+=bian[{min(v,fa[v]),max(v,fa[v])}];
        }
        a[v]=x;
        cout<<ans<<endl;
    }
}
posted @ 2025-07-18 11:29  White_ink  阅读(42)  评论(0)    收藏  举报