- 基环树上的环形DP
- 两次DP,一次断开,一次强制连接
点击查看代码
#include <bits/stdc++.h>
using namespace std;
vector<int>z[500005];
int n,m,c[1000005];
bool b[2000005],v[1000005];
int f[1000005][2],r[1000005];
int pd;
int h[2000005],nx[2000005],t[2000005],cnt;
int read1()
{
char cc=getchar();
while(!(cc>=48&&cc<=57))
{
if(cc=='-')
{
break;
}
cc=getchar();
}
bool f=false;
int s=0;
if(cc=='-')
{
f=true;
}
else
{
s=cc-48;
}
while(1)
{
cc=getchar();
if(cc>=48&&cc<=57)
{
s=s*10+cc-48;
}
else
{
break;
}
}
if(f==true)
{
s=-s;
}
return s;
}
void add(int u,int v)
{
cnt++;
nx[cnt]=h[u];
h[u]=cnt;
t[cnt]=v;
}
int dfs(int n1)
{
bool f=false;
v[n1]=true;
for(int i=h[n1];i!=0;i=nx[i])
{
int q=t[i];
if(b[i]==false)
{
b[i]=true;
if(i>n)
{
b[i-n]=true;
}
else
{
b[i+n]=true;
}
if(v[q]==false)
{
int tmp=dfs(q);
if(tmp>0)
{
if(c[n1]==tmp)
{
f=true;
}
c[n1]=tmp;
}
}
else
{
m++;
c[n1]=m;
c[q]=m;
}
}
}
if(c[n1]>0)
{
z[c[n1]].push_back(n1);
}
if(f==true)
{
return 0;
}
return c[n1];
}
void dp(int n1,int fa)
{
f[n1][0]=0;
f[n1][1]=1;
int minn=INT_MAX;
for(int i=h[n1];i!=0;i=nx[i])
{
int q=t[i];
if(b[i]==false&&q!=fa)
{
dp(q,n1);
f[n1][0]+=max(f[q][0],f[q][1]);
f[n1][1]+=max(f[q][0],f[q][1]);
minn=min(minn,max(f[q][0],f[q][1])-f[q][0]);
}
}
if(n1!=pd)
{
if(minn==INT_MAX)
{
f[n1][1]=-1000000;
}
else
{
f[n1][1]=f[n1][1]-minn;
}
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
r[i]=read1();
add(i,r[i]);
}
for(int i=1;i<=n;i++)
{
add(r[i],i);
}
for(int i=1;i<=n;i++)
{
if(!v[i])
{
int tmp=dfs(i);
}
}
memset(b,false,sizeof(b));
int sum=0;
for(int i=1;i<=m;i++)
{
int ans=0;
b[z[i][0]]=b[z[i][0]+n]=true;
pd=0;
dp(z[i][0],0);
ans=max(f[z[i][0]][0],f[z[i][0]][1]);
pd=r[z[i][0]];
dp(z[i][0],0);
ans=max(ans,f[z[i][0]][0]);
sum+=ans;
}
cout<<sum<<endl;
return 0;
}