E. Tree Shuffling(贪心)
思路:树上贪心的经典题目,根据贪心思想,显然已经满足条件的结点不需要动,然后我们对每个结点记录它的子树中含有两种不满足条件 ( 1 , 0 ) , ( 0 , 1 ) (1,0),(0,1) (1,0),(0,1)的类型结点数,
然后还需要记录从根结点到当前结点 u u u之前的最小 c o s t cost cost. 然后对每个结点判断一下,
如果结点 u u u的 c o s t < m i n c o s t cost<min_{cost} cost<mincost就用这个结点对它的子树洗牌,最后再判断一下两种类型的结点数在 d f s dfs dfs后是否都为0就即可。
时间复杂度: O ( n ) O(n) O(n)
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5,inf=0x3f3f3f3f;
#define mst(a) memset(a,0,sizeof a)
int a[N],b[N],c[N],n;
ll ans;
vector<int>e[N];
pair<int,int> dfs(int u,int fa,int mn){
pair<int,int>pi={0,0};
if(b[u]!=c[u]){
if(b[u]) pi.first++;
else pi.second++;
}
for(auto v:e[u]){
if(v==fa) continue;
pair<int,int>tmp=dfs(v,u,min(mn,a[u]));
pi.first+=tmp.first;
pi.second+=tmp.second;
}
if(a[u]<mn){
int cnt=min(pi.first,pi.second);
ans+=1LL*cnt*a[u]*2;
pi.first-=cnt,pi.second-=cnt;
}
return pi;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d%d",&a[i],&b[i],&c[i]);
for(int i=1,u,v;i<n;i++){
scanf("%d%d",&u,&v);
e[u].push_back(v),e[v].push_back(u);
}
pair<int,int>res=dfs(1,0,inf);
if(res.first||res.second) puts("-1");
else printf("%lld\n",ans);
return 0;
}