将每个人讨厌的人连上一条有向边,构成了基环树森林,从每个树的环上断一条边,从两条边的点跑两次dfs,计算一下最大值加到答案里
还有就是会超int
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e6+5;
const long long inf=1e17;
int n,root,cnt,v[maxn],fa[maxn],vis[maxn],head[maxn];
long long f[maxn][2];
struct edge
{
int to,nxt;
}e[maxn];
void add(int x,int y)
{
e[++cnt].to=y;
e[cnt].nxt=head[x];
head[x]=cnt;
}
long long ans;
void dfs(int x)
{
vis[x]=1;
f[x][1]=v[x]; f[x][0]=0;
for(int i=head[x];i;i=e[i].nxt)
{
int to=e[i].to;
if(to==root)
{
f[to][1]=-inf;
continue;
}
dfs(to);
f[x][0]+=max(f[to][0],f[to][1]);
f[x][1]+=f[to][0];
}
}
void circle(int x)
{
vis[x]=1;
root=x;
while(!vis[fa[root]])
{
root=fa[root];
vis[root]=1;
}
dfs(root);
long long ans1=max(f[root][0],f[root][1]);
vis[root]=1;
root=fa[root];
dfs(root);
long long ans2=max(f[root][0],f[root][1]);
ans+=max(ans1,ans2);
}
int main()
{
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d",&n);
int x;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&v[i],&x);
add(x,i); fa[i]=x;
}
for(int i=1;i<=n;i++)
if(!vis[i])
circle(i);
printf("%lld",ans);
return 0;
}