对于一些不符合的点来说,肯定是被他的父节点上权值最小的点转换最好。

首先我们先排除不可能情况也就是01不等

之后发现,交换完两个数后,0不符合的和1不符合的个数各自-1,因此不会影响其他交换

因此我们维护一个最小值,表示父亲节点的最小值,如果这个值比当前节点小,那么显然在子树内部交换更好

之后只要dfs维护一下需要交换的01个数就好

CF1363E  Tree Shuffling(贪心+树上乱搞)_i++CF1363E  Tree Shuffling(贪心+树上乱搞)_codeforces_02
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10;
typedef long long ll;
int h[N],ne[N],e[N],idx;
ll a[N],b[N],c[N];
int cnt0[N],cnt1[N];
ll res;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa,ll tmp){
    ll mi=min(tmp,a[u]);
    int i;
    for(i=h[u];i!=-1;i=ne[i]){
        int j=e[i];
        if(j==fa)
            continue;
        dfs(j,u,mi);
        cnt0[u]+=cnt0[j];
        cnt1[u]+=cnt1[j];
    }
    if(b[u]!=c[u]){
        if(b[u]==1)
            cnt1[u]++;
        else{
            cnt0[u]++;
        }
    }
    int x=min(cnt1[u],cnt0[u]);
    if(mi==a[u]){
        cnt1[u]-=x;
        cnt0[u]-=x;
        res+=2*x*a[u];
    }
}
int main(){
    int n;
    cin>>n;
    memset(h,-1,sizeof h);
    int i;
    int tmp1=0,tmp2=0;
    for(i=1;i<=n;i++){
        scanf("%lld%lld%lld",&a[i],&b[i],&c[i]);
        if(b[i])
            tmp1++;
        if(c[i])
            tmp2++;
    }
    for(i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add(u,v);
        add(v,u);
    }
    if(tmp1!=tmp2){
        cout<<"-1"<<endl;
    }
    else{
        dfs(1,-1,a[1]);
        cout<<res<<endl;
    }
}
View Code

 

没有人不辛苦,只有人不喊疼