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

    传送门

    考虑一个非根非叶子节点如何无限大,显然只要任意两个儿子权值不同即可

    考虑到根节点不会变,所以只要对根节点每一个儿子子树分别处理,如果子树内任意一个节点有两个权值不同的儿子直接输出 $+inf$

    考虑剩下的情况,子树如果是一颗普通树结构的话,那么每个节点都必须满足 $val[fa]+val[son]=2val[self]$ ,不然 $self$ 的权值就可以改变,然后整颗树就可以连锁反应导致两个儿子权值不同,直接 $+inf$

    发现只有当子树是一条链(可以有多个叶子连在末端节点上)的时候,节点权值才可以改变而不导致无限大

    考虑一次操作的影响,对于连续的三个节点 $x,y,z$ ,$fa[y]=x,fa[z]=y$,考虑他们权值的差分数组,$x-y,y-z$

    操作过后发现就变成了 $y-z,x-y$,显然这样交换可以任意排列差分数组,所以直接把差分值从大到小排序即可

    然后就是代码实现了,按着上面的步骤模拟就行,有点恶心

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=2e5+7;
    int n,a[N];//权值
    ll ans,res,b[N],ss;//答案,中间答案,差分数组,叶子节点权值和
    int fir[N],from[N<<1],to[N<<1],cntt;
    inline void add(int a,int b) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; }
    int rt,son[N],fa[N];//根,任意一个儿子,父亲
    bool GG,flag;//是否+inf,子树是否权值一样
    void dfs(int x)
    {
        int u=son[x]; res+=a[x];
        if(!son[x]) ss+=a[x];
        for(int i=fir[x];i;i=from[i])
        {
            int &v=to[i];
            if(a[v]!=a[u]) { GG=1; return; }
            if(a[fa[x]]+a[v]!=2*a[x]) flag=1;
            fa[v]=x; dfs(v);
        }
    }
    int dfs2(int x)//判断除去叶子是否是一条链
    {
        int cnt=0,pd=0;
        for(int i=fir[x];i;i=from[i])
            cnt++,pd|=dfs2(to[i]);
        if(pd&&cnt>=2) GG=1;
        return cnt>0;
    }
    inline bool cmp(ll &a,ll &b) { return a>b; }
    int val[N],tot;
    void dfs3(int x)//走链
    {
        val[++tot]=a[x];
        if(son[x]) dfs3(son[x]);
    }
    void solve(int x)//处理一个子树
    {
        flag=res=ss=0; fa[x]=rt;  dfs(x);
        if(GG) return;
        if(flag) dfs2(x);//如果权值会变,看看是否为链
        if(GG) return;
        if(!flag) { ans+=res; return; }//权值不变直接把整个子树权值计入答案
        tot=0; dfs3(x); val[0]=a[rt];
        for(int i=1;i<=tot;i++) b[i]=val[i]-val[i-1];//差分
        sort(b+1,b+tot+1,cmp); ll now=a[rt];
        for(int i=1;i<tot;i++) now+=b[i],ans+=now;
        ans+=ss;//记得加上叶子
    }
    inline void clr()
    {
        cntt=GG=flag=rt=ans=res=tot=ss=0;
        for(int i=1;i<=n;i++) a[i]=b[i]=son[i]=fa[i]=fir[i]=val[i]=0;
    }
    int main()
    {
        while(233)
        {
            n=read(); if(!n) break;
            int fa;
            for(int i=1;i<=n;i++)
            {
                fa=read(),a[i]=read();
                if(fa==-1) rt=i;
                else add(fa,i),son[fa]=i;
            }
            for(int i=fir[rt];i;i=from[i]) { solve(to[i]); if(GG) break; }
            if(GG) printf("+inf
    ");
            else printf("%lld
    ",ans+a[rt]);
            clr();
        }
        return 0;
    }
    View Code
  • 相关阅读:
    Sharepoint2013搜索学习笔记之创建搜索服务(二)
    Sharepoint2013搜索学习笔记之设置外网内容源(四)
    C# zxing插件 根据输入的字符串生成二维码
    值类型和引用类型
    Web.config增删查改
    Redis
    2017年最好的6个WEB前端开发手册下载
    php implode()函数详解
    elk日志系统搭建
    aop实现接口请求参数打印
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/11400478.html
Copyright © 2011-2022 走看看