版权声明:请大家斧正,如喜欢的话,为拙见点一个赞吧。 https://blog.csdn.net/qq_39897867/article/details/84674258
题目
http://www.joyoi.cn/problem/tyvj-1940
解题思路
我们可以用两次树形 来代替基环树 ,两次 ,一次断开,一次强制连接(通过适当的条件和赋值实现)。
代码
#include<cstdio>
#define rr register
using namespace std;
const int N=1000010;
struct node{int y,next;}a[N];
int n,tot,ans,d[N],head[N],mark,root,f[N],g[N],fa[N]; bool v[N];
inline int minn(int x,int y){if (x<y) return x; return y;}
void add(int x,int y){a[++tot]=(node){y,head[x]}; head[x]=tot;}
void check_ring(int x){v[x]=true; if (v[d[x]]) mark=x; else check_ring(d[x]);}
void dp(int x)
{
v[x]=true;
f[x]=1; g[x]=2147483647/3;
if (x==root) g[x]=0;
for (rr int i=head[x];i;i=a[i].next)
{
int y=a[i].y;
if (i==mark||y==fa[x]) continue;
fa[y]=x; dp(y);
g[x]+=minn(f[y],g[y]);
g[x]=minn(g[x],f[x]+f[y]-1);
f[x]+=minn(f[y],g[y]);
}
return;
}
int main()
{
scanf("%d",&n);
for (rr int i=1;i<=n;i++) scanf("%d",&d[i]),add(d[i],i);
for (rr int i=1;i<=n;i++)
{
if (v[i]) continue;
check_ring(i);
root=d[mark]; dp(mark);
int now=f[mark];
root=0; dp(mark);
ans+=minn(now,g[mark]);
}
printf("%d",n-ans);
}