一道树形dp,但是有坑点,就是他可能是个环,所以我们要将环拆成链,然后我们发现从链的首尾进去都可以是一条链,所以我们要从首尾进去,取max
代码
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define lli long long int
using namespace std;
const int M=1e6+50;
bool vis[M*2];
lli f[M][2],ans,e;
int rt,trt,n,c[M],fl;
int to[M*2],nxt[M*2],head[M],cnt,id[M*2];
inline int read()
{
lli x=0;char ch=getchar();
while (ch>'9'||ch<'0') ch=getchar();
while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x;
}
inline void add(int x,int y,int idy)
{
to[++cnt]=y;nxt[cnt]=head[x];head[x]=cnt;id[cnt]=idy;//记录边的编号
to[++cnt]=x;nxt[cnt]=head[y];head[y]=cnt;id[cnt]=idy;//防止走断掉的边
return ;
}
inline void dfs(int x,int fa)
{
vis[x]=1;
for (int i=head[x];i;i=nxt[i])
{
if (to[i]==fa) continue;
if (vis[to[i]])
rt=to[i],trt=x,fl=id[i];//一个环的两个端点,断环
else dfs(to[i],x);
}
return ;
}
inline void tdp(int x,int fa)
{
f[x][0]=0;f[x][1]=c[x];
for (int i=head[x];i;i=nxt[i])
{
if (id[i]==fl||to[i]==fa) continue;
tdp(to[i],x);f[x][1]+=f[to[i]][0];
f[x][0]+=max(f[to[i]][0],f[to[i]][1]);
}
return ;
}
signed main()
{
n=read();int x;
for (int i=1;i<=n;i++)
c[i]=read(),x=read(),add(x,i,i);
for (int i=1;i<=n;i++)
if (!vis[i])
{
dfs(i,0);tdp(rt,0);e=f[rt][0];
tdp(trt,0);e=max(e,f[trt][0]);
//看环的首还是尾不选,取max
ans+=e;
}
cout<<ans;
return 0;
}
//-----------------------------------------------------------------------------------------------------------------
// =============== # # ||\\ || ||============ || ==========
// =============== # # || \\ || || ||// \\
// | | # # || \\ || || || \\
// | | # # || \\ || || || ||
// | | # # || \\ || || || ||
// | | # # || \\ || ||============ ||\\=========//
// | | # # || \\ || || || \\
// | | # # || \\ || || || \\
// | | \ / || \\ || || || \\
// \ \ / / \ / || \\ || || || \\
// \__ / =========== || \\|| ||============ || \\
//----------------------------------------------------------------------------------------------------------------