题意 :传送门
题解:这道题是传送门的升级版,参考传送门,由于基环树森林最多只有一个基环,所以直接断开算,最后累加森林答案即可。
附上代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+5;
struct edge{int v,next;}e[maxn*2];
int head[maxn],tot;
void add_edge(int u,int v)
{
e[++tot].v=v;e[tot].next=head[u];head[u]=tot;
e[++tot].v=u;e[tot].next=head[v];head[v]=tot;
}
int n,u,v,f[maxn],hte[maxn],dep[maxn];
bool vis[maxn];
ll dp[maxn][2],ans;
void dfs(int x,int p)
{
vis[x]=true;
for(int i=head[x];i;i=e[i].next){
int y=e[i].v;
if(y==p)continue;
if(vis[y]){
if(dep[y]<dep[x])u=x,v=y;
continue;
}
dep[y]=dep[x]+1;
dfs(y,x);
}
}
void solve(int x,int p)
{
dp[x][1]=f[x];dp[x][0]=0;
for(int i=head[x];i;i=e[i].next){
int y=e[i].v;
if((x==u&&y==v)||(x==v&&y==u)||y==p)continue;
solve(y,x);
dp[x][0]+=max(dp[y][0],dp[y][1]);
dp[x][1]+=dp[y][0];
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++){
int x;
scanf("%d%d",&f[i],&hte[i]);
if(hte[hte[i]]==i)continue;
add_edge(hte[i],i);
}
for(int i=1;i<=n;i++){
if(vis[i])continue;
u=v=0;
dfs(i,0);
ll res=0;
if(!u&&!v){
solve(i,0);
res=max(dp[i][0],dp[i][1]);
}else{
solve(u,0);
res=dp[u][0];
solve(v,0);
res=max(res,dp[v][0]);
}
ans+=res;
}
printf("%lld\n",ans);
return 0;
}