题意:给你的一个包含n个数由1到n组成的数组,有m个操作,每个操作对应交换数组下标x和下标y,问经过任意次这些操作,最多能有多少下标满足(数组下标=对应下标的数)
Sample Input 1
Copy
5 2 5 3 1 4 2 1 3 5 4
Sample Output 1
Copy
2
If we perform the operation by choosing j=1, p becomes 1 3 5 4 2
, which is optimal, so the answer is 2.
思路:由于可以任意交换两位不限次数,那么只要是可以操作的下标集合,对应下标的数就一定可以到达集合任意位置。所以只要求出所有集合,然后判断下标和对应数是否在集合内。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
using namespace std;
const int MAXN = 100005;
const int inf = 0x3f3f3f3f;
typedef long long LL;
int a[MAXN];
struct node{
int from,to;
}edge[MAXN*2];
int head[MAXN];
int vis[MAXN];
int bin[MAXN];
int cnt;
void add(int u, int v)
{
edge[cnt].to=v;
edge[cnt].from=head[u];
head[u]=cnt++;
}
int findx(int x)
{
if(bin[x]==x)
return x;
return bin[x]=findx(bin[x]);
}
void merge(int u, int v)
{
int fx=findx(u);
int fy=findx(v);
if(bin[fy]!=fx)
bin[fy]=fx;
}
void dfs(int u)
{
vis[u]=1;
for(int i=head[u];~i;i=edge[i].from)
{
int v=edge[i].to;
if(!vis[v])
{
bin[v]=cnt;
dfs(v);
}
}
}
int main()
{
int n, m;
cnt=0;
memset(head, -1, sizeof(head));
memset(vis,0,sizeof(vis));
scanf("%d %d", &n, &m);
for(int i=1;i<=n;++i)
{
scanf("%d", &a[i]);
bin[i]=i;
}
for(int i=0;i<m;++i)
{
int x, y;
scanf("%d %d", &x, &y);
add(x,y);
add(y,x);
}
int ans=0;
cnt=1;
for(int i=1;i<=n;++i)
{
if(!vis[i])
{
bin[i]=cnt;
dfs(i);
cnt++;
}
if(bin[a[i]]==bin[i])
ans++;
}
printf("%d\n", ans);
return 0;
}