由于一个骑士只会痛恨另一个骑士,所以痛恨的关系等于骑士数量。可知这是一张由n个点,n条边组成的环套树森林。
环套树是什么?环套树是一种有且只有一个环的图(并没有找到环套树的标准定义-_-)。大概脑补一下,就是一个环,上面的一些节点套着一棵树。。。
记f[i][1或0]表示节点i取或不取,它以及他的子树的贡献答案。
环套树问题一般都涉及拆环上的边。此题中,可以随意删除环上的一条边,记被删除的边两端节点为u,v,那这一棵环套树的答案就是max(f[u][0],f[v][0]),因为u和v至少有一个不会被取。
把每棵环套树都做过去就好了,记得开long long。
#include<cstdio>
#include<algorithm>
#define MAXN 1000010
using namespace std;
int n, a[MAXN], edge_cnt=1, u, v, cut, q[MAXN], last[MAXN], vis[MAXN], vis_cnt=1;
long long f[MAXN][2];
struct edge{int next,to;}e[MAXN<<1];
void add(int a, int b)
{
e[++edge_cnt]=(edge){last[a],b};
last[a]=edge_cnt;
}
void bfs(int beg)
{
q[0]=beg;
vis[beg]=++vis_cnt;
for(int head=0, tail=1; head<tail; head++)
{
int x=q[head];
for(int i = last[x]; i; i=e[i].next)
{
int y=e[i].to;
if(vis[y] && vis[y]+1==vis[x])
continue;
else if(vis[y])
{
u=x;
v=y;
cut=i;
}
else
{
q[tail++]=y;
vis[y]=vis[x]+1;
}
}
}
}
void dp(int x, int fa)
{
f[x][1]=a[x];
f[x][0]=0;
for(int i = last[x]; i; i=e[i].next)
{
if(i==cut || (i^1)==cut || e[i].to==fa)continue;
int y=e[i].to;
dp(y,x);
f[x][1]+=f[y][0];
f[x][0]+=max(f[y][0],f[y][1]);
}
}
int main()
{
long long ans=0, pre;
scanf("%d",&n);
for(int i = 1, x; i <= n; i++)
{
scanf("%d%d",&a[i],&x);
add(i,x);
add(x,i);
}
for(int i = 1; i <= n; i++)
if(!vis[i])
{
bfs(i);
dp(u,-1);
pre=f[u][0];
dp(v,-1);
ans+=max(pre,f[v][0]);
}
printf("%lld\n",ans);
return 0;
}