洛谷AT4131 Equals
洛谷翻译:
题意:
给你一个数列,然后给你若干个操作,每一个操作的两个数代表数列中的下标,操作是两个数交换,题目问最后能够把数字i放在第I位的数字有多少个,就是下标等于数字本身。(交换次数无限)
比如操作
1 2
2 4
两个操作,显而易见1 和4也可以交换,也就是说,把每个操作合并起来,只要在集合里,那么一定可以换到。
所以就是并查集,框架差不多。合并可以套模板。
难点在于如何计算符合要求的个数。
我们要让下标和本身相等,那么我们就提前把原数组每个数下标存在
s
i
g
n
[
]
sign[]
sign[]里面,只要发现这个数
i
i
i的下标和
i
i
i在一个集合,那么,就说明这个数
i
i
i可以到达下标
i
i
i,ans++。
#include<iostream>
using namespace std;
int a[100002],parent[100002],sign[100002];
int cmp1,cmp2;
int find(int x)
{
while(x!=parent[x]){
x=parent[x]=parent[parent[x]];//路径压缩
}
return x;
}
void root(int x,int y)
{
int x_root=find(x);
int y_root=find(y);
if(x_root!=y_root)parent[x_root]=y_root;//
}
int main()
{
int ans=0;
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
parent[i]=i;
sign[a[i]]=i;//存每个数的下标
}
for(int i=1;i<=m;i++){
cin>>cmp1>>cmp2;
root(cmp1,cmp2);
}
for(int i=1;i<=n;i++){
if(find(i)==find(sign[i]))ans++;//下标i和本数i在一个集合的话就是可以
}
cout<<ans;
}
(广东工业大学ACM寒假集训专题三E)