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\n"); else printf("%lld\n",ans+a[rt]); clr(); } return 0; }