贪心+树形dp——cf1353E

昨天早知道先做这题的。。

随便写写就能过

/*
贪心:结点按a升序排序依次处理
s[u]表示u子树b=1结点个数
t[u]表示u子树c=1节点个数  
dif[u]表示u子树bc不同的个数
vis[u]表示u所有子孙被访问了 
每次遍历到u,先求一次s,t,dif 
    如果s[u]=t[u],那么u的贡献就是a[u]*dif[u]
    反之就是a[u]*(dif[u]-abs(s[u]-t[u])) 
然后给u子树的所有子孙标记 
*/ 
#include<bits/stdc++.h>
using namespace std;
#define N 200005
#define ll long long

vector<int>G[N];
ll n,a[N],b[N],c[N],s[N],t[N],dif[N],vis[N],id[N],fa[N];
int cmp(int x,int y){return a[x]<a[y];}

void dfs(int u,int pre){
    if(b[u])s[u]++;
    if(c[u])t[u]++;
    if(b[u]!=c[u])dif[u]++;
    fa[u]=pre;
    for(auto v:G[u])
        if(v!=pre){
            dfs(v,u);
            s[u]+=s[v];
            t[u]+=t[v];
            dif[u]+=dif[v];
        }
}
int getdif(int u,int pre){
    if(vis[u])return dif[u];
    int res=(b[u]!=c[u]);
    for(auto v:G[u])
        if(v!=pre)
            res+=getdif(v,u);
    return res;
}
void dfs2(int u,int pre){
    vis[u]=1;
    for(auto v:G[u])if(!vis[v])
        if(v!=pre)dfs2(v,u);
}

ll sum;

int main(){
    int n;cin>>n;
    for(int i=1;i<=n;i++)scanf("%lld%lld%lld",&a[i],&b[i],&c[i]),id[i]=i;
    for(int i=1;i<n;i++){
        int u,v;scanf("%lld%lld",&u,&v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    sort(id+1,id+1+n,cmp);

    dfs(1,1);
    
    if(s[1]!=t[1]){puts("-1");return 0;}
    
    for(int j=1;j<=n;j++){
        int i=id[j];
        if(vis[i])continue;
        int diff=getdif(i,fa[i]);
        sum+=a[i]*(diff-abs(s[i]-t[i])); 
        dif[i]=abs(s[i]-t[i]);
        dfs2(i,fa[i]);
    }
    
    cout<<sum<<'\n';
}

 

posted on 2020-06-01 14:21  zsben  阅读(143)  评论(0编辑  收藏  举报

导航