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\n",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\n",ans); continue; o:{ puts("+inf"); continue; } } return 0; }