题目:
Problem Statement
We have a permutation of the integers from 11 through NN, p_1p1, p_2p2, .., p_NpN. We also have MM pairs of two integers between 11 and NN (inclusive), represented as (x_1,y_1)(x1,y1), (x_2,y_2)(x2,y2), .., (x_M,y_M)(xM,yM). AtCoDeer the deer is going to perform the following operation on pp as many times as desired so that the number of ii (11 ≤≤ ii ≤≤ NN) such that p_i = ipi=i is maximized:
- Choose jj such that 11 ≤≤ jj ≤≤ MM, and swap p_{x_j}pxj and p_{y_j}pyj.
Find the maximum possible number of ii such that p_i = ipi=i after operations.
Constraints
- 22 ≤≤ NN ≤≤ 10^5105
- 11 ≤≤ MM ≤≤ 10^5105
- pp is a permutation of integers from 11 through NN.
- 11 ≤≤ x_j,y_jxj,yj ≤≤ NN
- x_jxj ≠= y_jyj
- If ii ≠= jj, \{x_i,y_i\}{xi,yi} ≠= \{x_j,y_j\}{xj,yj}.
- All values in input are integers.
Input
Input is given from Standard Input in the following format:
NN MM p_1p1 p_2p2 .... p_NpN x_1x1 y_1y1 x_2x2 y_2y2 :: x_MxM y_MyM
Output
Print the maximum possible number of ii such that p_i = ipi=i after operations.
Sample 1
Inputcopy | Outputcopy |
---|---|
5 2 5 3 1 4 2 1 3 5 4 | 2 |
If we perform the operation by choosing j=1j=1, pp becomes 1 3 5 4 2
, which is optimal, so the answer is 22.
Sample 2
Inputcopy | Outputcopy |
---|---|
3 2 3 2 1 1 2 2 3 | 3 |
If we perform the operation by, for example, choosing j=1j=1, j=2j=2, j=1j=1 in this order, pp becomes 1 2 3
, which is obviously optimal. Note that we may choose the same jj any number of times.
Sample 3
Inputcopy | Outputcopy |
---|---|
10 8 5 3 6 8 7 10 9 1 2 4 3 1 4 1 5 9 2 5 6 5 3 5 8 9 7 9 | 8 |
Sample 4
Inputcopy | Outputcopy |
---|---|
5 1 1 2 3 4 5 1 5 | 5 |
We do not have to perform the operation.
题意:给出一段n个数字序列,后有m个操作,每个操作给出xy两个数字,表示xy这两个数子代表的位数上的数字可以交换,求问我们最多可以让多少个数字与位数相同,即1在第一个数组,2在第二个数字。。。
题解:只要两个数字能交换,这两个数字可以组成任何排列,三个及三个以上的数组同理。那么只要i能与第i位数字进行交换,那么他就一定可以到原来的位置上。那么我们只要将可以交换的数字作一个集合,判断i与第i位数字上的父亲节点是否相同即可。
代码:
#include <iostream>
#include <algorithm>
using namespace std;
int q[100001],qq[100001];
inline int read(){//快读
int s=0,w=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
return s*w;
}
inline int find(int a)//找到最终父亲节点
{
if (q[a]!=a) q[a]=find(q[a]);
return q[a];
}
inline void jiehe(int x,int y)//将x与y放入同一集合内
{
x=find(x);y=find(y);
if (x==y) return;
if (x>y) {int tem=x;x=y;y=tem;}
q[x]=q[y];
}
int main()
{
int n,m,x,y;
cin >> n >> m;
for (int i=1;i<=n;i++)
{
qq[i]=read();q[i]=i;
}
for (int i=1;i<=m;i++)
{
x=read();y=read();
jiehe(x,y);
}
int sum=0;
for (int i=1;i<=n;i++)
{
if (qq[i]==i) sum++; else//若i就在第i位直接累加
if (find(q[i])==find(qq[i])) sum++;//若i与第i位数字的父亲节点相同,表示他们在同一集合内,同样累加
}
cout << sum;
}