按照hzw的说法,这其实是个无向的环+树+森林。
于是我们可以强制断环,断开环上的一条边,并且强制边上的一个端点是否存在。
然后就是裸的树形DP了
对于森林,我们加上一个vis标记就行了
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define N 1000005
#define ll long long
using namespace std;
struct edge{int to,next;}e[N*2];
int head[N],tot=1,n,a[N],v[N],U,V,E,x;
ll f[N],g[N],ans;
void add(int x,int y){
e[++tot].to=y;
e[tot].next=head[x];
head[x]=tot;
}
void dfs(int x,int from){
v[x]=1;
for (int i=head[x];i;i=e[i].next)
if ((i^1)!=from){
if (v[e[i].to]){
U=x;
V=e[i].to;
E=i;
continue;
}
dfs(e[i].to,i);
}
}
void dp(int x,int from,int ban){
f[x]=a[x];
g[x]=0;
for (int i=head[x];i;i=e[i].next)
if ((i^1)!=from&&i!=ban&&(i^1)!=ban){
dp(e[i].to,i,ban);
f[x]+=g[e[i].to];
g[x]+=max(f[e[i].to],g[e[i].to]);
}
}
int main(){
scanf("%d",&n);
for (int i=1;i<=n;i++){
scanf("%d%d",&a[i],&x);
add(i,x);
add(x,i);
}
for (int i=1;i<=n;i++)
if (!v[i]){
dfs(i,0);
dp(V,0,E);
ll tmp=g[V];
dp(U,0,E);
tmp=max(tmp,g[U]);
ans+=tmp;
}
printf("%lld",ans);
}