对于一些不符合的点来说,肯定是被他的父节点上权值最小的点转换最好。
首先我们先排除不可能情况也就是01不等
之后发现,交换完两个数后,0不符合的和1不符合的个数各自-1,因此不会影响其他交换
因此我们维护一个最小值,表示父亲节点的最小值,如果这个值比当前节点小,那么显然在子树内部交换更好
之后只要dfs维护一下需要交换的01个数就好
#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; } }