并查集入门例题2 洛谷AT4131 Equals

洛谷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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值