本题解在求无解的情况下优化了下。
通过分析样例,我们可以发现如果一个节点有多个 Dlihc,那么这些 Dlihc 对应的权值必须一样,否则可以无限延伸下去。
因为一号节点没有 Tnerap,所以一号节点一定不能更新,加上关系成树型结构那我们可以看成一个根节点把一棵树分成了几个子任务。
若子树不为链,就一定有一个节点有多个 Dlihc,设这个节点为 \(x\)。
那如果要判断无解:
1、\(x\) 的子节点有权值不相同。
2、\(x\) 的子节点相同,且子节点有子节点,并且此子任务中有节点可以更新。
证明:第一个易证,第二个若 \(x\) 的子节点有子节点,代表 \(x\) 的子节点可以更新。若子节点的子节点的权值与 \(x\) 节点权值加起来为子节点权值相同,才有可能有解。若此时 \(x\) 节点和子节点的子节点更新,那么必定无解。若不能更新,那可能有解,但若 \(x\) 的父节点与子节点的子节点的子节点可以更新,那无解。综上,只要这个字任务的树中有节点可以更新,那么就无解。
然后就是求答案,首先如果一个子任务不为链且 \(x\) 的子节点有子节点,那么无法更新,直接累加即可。
若不为链但 \(x\) 的子节点无子节点,由于 \(x\) 的子节点无法更新,可以取任意一个子节点即可,化作为链求解。
求解过程与其他人差不多,对链上的数进行查分,将差分后的数从大到小排序后,求所有的差分前缀和即可。
程序中先将所有点的初始值加起来,如果要进行差分加排序操作,再减去。
#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#define int long long
using namespace std;
const int N=2e5+5;
int n,pre[N],num[N],ans,sum[N],pef[N];
vector<int>suf[N];
bool flag,lim,flag2;
//flag 代表是否为不是链的情况,
//lim 代表这棵树是否能更新,
//flag2 代表x的子节点是否有子节点。
bool dfs(int x,int step)
{
sum[step]=num[x]-num[pre[x]];
pef[step]=x;
int len=suf[x].size();
if(len==0&&!flag)
{
sort(sum+1,sum+1+step);
int tac=num[1];
for(int i=step;i>0;i--)tac+=sum[i],ans+=tac-num[pef[i]];
return true;
}
if(flag==1&&len!=0)flag2=1;
if(flag2==1&&lim==1)return false;
if(len>1)flag=1;
bool ss=1;
for(int i=0;i<len;i++)
{
if(num[pre[x]]+num[suf[x][i]]!=2*num[x])lim=1;
ss&=dfs(suf[x][i],step+1);
if(num[suf[x][0]]!=num[suf[x][i]])return false;
}
if(len>1&&!flag2)
{
sort(sum+1,sum+1+step+1);
int tac=num[1];
for(int i=step+1;i>0;i--)tac+=sum[i],ans+=tac-num[pef[i]];
}
return ss;
}
signed main()
{
while(1)
{
scanf("%lld",&n);
if(n==0)break;
ans=0;
for(int i=1;i<=n;i++)suf[i].clear(),scanf("%lld%lld",&pre[i],&num[i]),suf[pre[i]].push_back(i),ans+=num[i];
int len=suf[1].size();
bool st=1;
for(int i=0;i<len;i++)
{
flag=flag2=lim=0;
if(!dfs(suf[1][i],1))st=0;
}
if(!st)printf("+inf\n");
else printf("%lld\n",ans);
}
return 0;
}
标签:JSOI2010,P7221,int,题解,sum,step,num,tac,节点
From: https://www.cnblogs.com/gmtfff/p/p7221.html