zoukankan      html  css  js  c++  java
  • Codeforces Round #646 (Div. 2) E. Tree Shuffling dfs

    题意:

    给你n个节点,这n个节点构成了一颗以1为树根的树。每一个节点有一个初始值bi,从任意节点 i 的子树中选择任意k个节点,并按他的意愿随机排列这些节点中的数字,从而产生k⋅ai 的成本。对于一个节点i你需要将bi改成ci。

    这个bi值和ci值的范围是[0,1]

    题解:

    对于一个节点,如果它的bi==ci,那么我们就不用管它(因为你改变它的值,那么肯定之后还要花费成本再改回来,增加了成本)。那么我们首先找出来一共有多少个节点bi!=ci ,然后总权值肯定是

    num1*a1+num2*a2...+numn*an

    numi表示从节点 i 的子树中选择任意numi个节点

    那么肯定是尽可能在ai的值越小的子树上尽量增加numi的数量,这样总权值肯定最小

    cnt0[i]:以i节点为树根的子树,在bi!=ci,bi等于0的数量

    cnt1[i]:以i节点为树根的子树,在bi!=ci,bi等于1的数量

    那么我们就从树根开始dfs,并且维护一个ai最小值,在dfs过程中记录一下i这个节点的所有子节点上bi!=ci的数量(如果bi!=ci,还要记录一下i这个点的bi值),如果ai等于我们维护的那个ai最小值,那就对这个节点

    的2*min(cnt0[i],cnt1[i])个节点进行排序。然后让cnt1[i]和cnt0[i]都减去min(cnt0[i],cnt1[i])

    最后判断一下cnt1[1]和cnt0[1]是否为0,等于0就代表所有节点bi都等于ci,否则输出-1

    代码:

    #include<stdio.h>
    #include<algorithm>
    #include<iostream>
    #include<string>
    #include<queue>
    #include<deque>
    #include<string.h>
    #include<map>
    #include <iostream>
    #include <math.h>
    #define Mem(a,b) memset(a,b,sizeof(a))
    const double II = acos(-1);
    const double PP = (II*1.0)/(180.00);
    using namespace std;
    typedef long long ll;
    const int INF=0x3f3f3f3f;
    const int maxn=2e5+10;
    ll a[maxn],b[maxn],c[maxn],cnt0[maxn],cnt1[maxn],sum;
    vector<ll>w[maxn];
    void dfs(ll x,ll fa,ll minn)
    {
        minn=min(minn,a[x]);
        for(ll i=0;i<w[x].size();++i)
        {
            ll now=w[x][i];
            if(now!=fa)
            {
                dfs(now,x,minn);
                cnt0[x]+=cnt0[now];
                cnt1[x]+=cnt1[now];
            }
        }
        if(b[x]!=c[x])
        {
            if(b[x])
                cnt1[x]++;
            else cnt0[x]++;
        }
        if(minn==a[x])
        {
            ll ans=min(cnt0[x],cnt1[x]);
            ans*=2;
            //printf("%d %d****
    ",ans,a[x]);
            sum=sum+ans*a[x];
            ans/=2;
            cnt0[x]-=ans;
            cnt1[x]-=ans;
        }
    }
    int main()
    {
        ll n;
        sum=0;
        scanf("%I64d",&n);
        for(ll i=1;i<=n;++i)
        {
            scanf("%I64d%I64d%I64d",&a[i],&b[i],&c[i]);
        }
        for(ll i=1;i<n;++i)
        {
            ll u,v;
            scanf("%I64d%I64d",&u,&v);
            w[u].push_back(v);
            w[v].push_back(u);
        }
        dfs(1,0,INF);
        if(cnt1[1] || cnt0[1])
        {
            printf("-1
    ");
        }
        else printf("%I64d
    ",sum);
    }
  • 相关阅读:
    【Demo 0035】获取窗体状态
    【Demo 0030】获取其他进程窗体信息(防SPY++)
    【Demo 0034】窗体支持文件拖拽
    【Demo 0036】Window层窗体
    【Demo 0032】遍历子窗体
    二维数组定义以及动态分配空间 (转)
    Visual Studio 2008 环境变量的配置(dll加载方式) [转]
    修改MFC标题栏上的图标
    VC环境下的头文件包含(转)
    VC++单选按钮控件(Ridio Button)的使用(转载)
  • 原文地址:https://www.cnblogs.com/kongbursi-2292702937/p/13360545.html
Copyright © 2011-2022 走看看