0
点赞
收藏
分享

微信扫一扫

GDUT-寒假专题训练3--Equals

自由情感小屋 2022-02-27 阅读 58
算法c++

题目:

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

InputcopyOutputcopy
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

InputcopyOutputcopy
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

InputcopyOutputcopy
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

InputcopyOutputcopy
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;
}
举报

相关推荐

0 条评论