题面
题意
给出n个数,i可以到达第i个数,且这n个数为1到n的一个排列,现在可以交换两个数,问最多有几组点可以两两相互到达.
方法
一开始没有做出来是因为没有发现这n个数都不同,有了这个条件就说明,从i点出发必然能够回到i,因而可以将它理解为几个环,每个环上的点都两两能够到达,种类数为其大小的平方,一次交换可以将两个不同环变成一个大环,只要将两最大环合并计算种树即为答案
上述条件仅用并查集就能实现
代码
#include<bits/stdc++.h>
#define ll long long
#define N 100010
using namespace std;
ll fa[N],n,pos[N],cnt[N],ans;
ll get(ll u)
{
return u==fa[u]?u:fa[u]=get(fa[u]),fa[u];
}
int main()
{
ll i,j;
cin>>n;
for(i=1;i<=n;i++) fa[i]=i;
for(i=1;i<=n;i++)
{
scanf("%d",&pos[i]);
fa[get(i)]=get(pos[i]);
}
for(i=1;i<=n;i++)
{
cnt[get(i)]++;
}
sort(cnt+1,cnt+n+1);
ans=(cnt[n]+cnt[n-1])*(cnt[n]+cnt[n-1]);
for(i=n-2;i>=1;i--)
{
ans+=cnt[i]*cnt[i];
}
printf("%lld",ans);
}