zoukankan      html  css  js  c++  java
  • bzoj1825: [JSOI2010]蔬菜庆典

    Description

    Input

    Output

    对于每组数据,输出一行。若蔬菜的总价能无限制增大,输出"+inf"(不含引号)。否则输出一个整数,表示所有蔬菜的最大总价。
     

    首先如果一个非根的点有多个权值不同的孩子,显然答案为+inf,否则为了便于讨论将原树进行一些转换(代码实现中只是隐式处理):

    根的权值不会改变,根的子树间互不影响。可以删去根(并计入答案),对每个原先父亲为根的点,新建一个点作为其父亲,权值与根相同(新建的点不计入答案)

    叶子的权值不会改变。如果一个点的所有孩子都是叶子,只保留一个孩子(被删去的叶子直接计入答案)

    由此得到一个有根森林。对每个连通块,如果每个点至多有一个孩子,构成一条链,那么在链上操作相当于交换相邻两条边的边权(边权定义为两端点权之差),无论如何都无法达到inf,可以贪心将边权排序得到最大值。否则,存在至少一个点有2个或更多孩子,这时当且仅当所有边权相同时答案不是inf(此时操作无效)(若有不同的边权,可通过操作传递至有两个孩子的点上,导致答案为inf(严格的说,不在链上时,操作除了交换两边边权还可能影响其他边权,但并不影响上述结论成立))

    #include<cstdio>
    #include<algorithm>
    int _(){
        int x;
        scanf("%d",&x);
        return x;
    }
    typedef long long i64;
    const int N=200007,v0=0x3f3f3f3f;
    int n;
    int fa[N],son[N],v[N],sv[N],deg[N],cl[N];
    int ss[N],sp;
    bool nl[N];
    i64 ans;
    #define ass(x) if(x)n/=0
    int main(){
        //freopen("in.txt","r",stdin);
        while(n=_()){
            _();
            ans=v[1]=_();
            bool _inf=0;
            for(int i=2;i<=n;++i){
                sv[i]=v0;deg[i]=cl[i]=son[i]=0;
                int f=fa[i]=_();
                ass(f>i);
                v[i]=_();
                if(f==1)continue;
                ++deg[f];
                son[f]=i;
                if(sv[f]==v0)sv[f]=v[i]-v[fa[i]];
                else if(sv[f]!=v[i]-v[fa[i]])_inf=1;
            }
            if(_inf)goto o;
            for(int i=2;i<=n;++i)if(!deg[i])ans+=v[i],++cl[fa[i]];
            //for(int i=2;i<=n;++i)printf("%d:%d %d
    ",i,deg[i],cl[i]);
            for(int i=2;i<=n;++i)nl[i]=nl[fa[i]]||deg[i]-cl[i]-!cl[i]>0;
            for(int i=n;i>=2;--i)nl[fa[i]]|=nl[i];
            nl[1]=0;
            for(int i=2;i<=n;++i)if(deg[i]){
                if(nl[i]){
                    ans+=v[i];
                    if(sv[i]!=v[i]-v[fa[i]])goto o;
                }else if(fa[i]==1){
                    sp=0;
                    for(int w=i;w;w=son[w])ss[sp++]=v[w]-v[fa[w]];
                    std::sort(ss,ss+sp);
                    for(i64 x=v[1];sp>1;ans+=x+=ss[--sp]);
                }
            }
            printf("%lld
    ",ans);
            continue;
            o:{
                puts("+inf");
                continue;
            }
        }
        return 0;
    }
  • 相关阅读:
    取模 分数取模 快速幂 费马小定理
    “科林明伦杯”哈尔滨理工大学第十届程序设计竞赛 部份签到题
    shell 脚本
    pyhcl语法
    数据库实验1 SQL
    杂七杂八 Ubuntu Linux
    Kattis, Kattis 的一些问题题解
    Meow Factor 【暴力】
    解决 Eclipse 项目有红感叹号的方法
    RuntimeException与CheckedException
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7148581.html
Copyright © 2011-2022 走看看