E - Tree Shuffling

题:https://codeforces.com/contest/1363/problem/E

题意:给定一棵树,每个节点有ai,bi,ci的属性,代表节点 i 想将自己的bi 通过和自己子树的 值交换而变成ci。类似地,这种交换的代价为2*ai。允许的操作为选择一个节点x,可以选择任意k个该子树节点数,进行这种交换。问最小代价或输出-1代表不能达到要求。

分析:题目中c的取值为0或1,若能达到要求就表示整个树0->1 和1->0的对数要一样。接着就可以递归地让最小的消耗去完成交换对数,这个对数不是选0->1就是选1->0,所以只要取俩者最小即可。

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=1e18;
const int M=2e5+5;
vector<int>g[M];
ll dp[M],a[M];
int b[M],c[M],cnt[M][2];
void py(){
    cout<<"Yes"<<'\n';
}
void pn(){
    cout<<"No"<<'\n';
}
ll ksm(ll x,ll y){
    ll t=1ll;
    while(y){
        if(y&1)
            t=t*x;
        y>>=1;
        x=x*x;
    }
    return t;
}
ll ans;
void dfs(int u,int fa){
    if(fa)
        a[u]=min(a[u],a[fa]);
    int flag=-1;
    if(!b[u]&&c[u])
        flag=0;
    if(b[u]&&!c[u])
        flag=1;
    int countt0=0,countt1=0;
    for(auto v:g[u]){
        if(v!=fa){
            dfs(v,u);
            cnt[u][0]+=cnt[v][0];
            cnt[u][1]+=cnt[v][1];
            int tmp=cnt[v][0]-cnt[v][1];
            if(tmp>0)
                countt0+=tmp;
            else
                countt1-=tmp;
        }
    }
    if(flag==0)
        cnt[u][0]++,countt0++;
    if(flag==1)
        cnt[u][1]++,countt1++;
    ///cout<<u<<"!!!"<<countt0<<"!!"<<countt1<<endl;
    ///cout<<a[u]<<"@@"<<ans<<endl;
    ans+=2ll*a[u]*min(countt1,countt0);
}
int main(){
    int n;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld%d%d",&a[i],&b[i],&c[i]),dp[i]=INF;
    for(int u,v,i=1;i<n;i++){
        scanf("%d%d",&u,&v);
        g[u].pb(v),g[v].pb(u);
    }
    dfs(1,0);
    printf("%lld\n",cnt[1][0]!=cnt[1][1]?-1:ans);
    return 0;
}
View Code

 

posted @ 2020-06-01 14:22  starve_to_death  阅读(216)  评论(0编辑  收藏  举报