XJOI 3578 排列交换/AtCoder beginner contest 097D equal (并查集)
Posted stxy-ferryman
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了XJOI 3578 排列交换/AtCoder beginner contest 097D equal (并查集)相关的知识,希望对你有一定的参考价值。
题目描述:
你有一个1到N的排列P1,P2,P3...PN,还有M对数(x1,y1),(x2,y2),....,(xM,yM),现在你可以选取任意对数,每对数可以选取任意次,然后对选择的某对数(xi,yi)进行操作,操作方式为交换xi,yi两个位置的数。最终你想要Pi=i的位置尽可能多。输出最多可以有多少个这样的位置
输入格式:
第一行输入一个整数N,第二行输入一个整数M
接下来M行每行输入一对数xi,yi
输出格式:
输出一个整数
样例输入1:
5 2
5 3 1 4 2
1 3
5 4
样例输出1:
2
样例输入2:
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
样例输出2:
8
约定:
2<=N<=105,1<=M<=105,xi!=yi
牢骚:emmm,在看到这题的第一秒我整个人就感觉不好了
记得那是我的第一场abc,报完名用fuko大佬的电脑看了开始时间,嗯,九点
后来才知道fuko大佬的电脑是东京时间QAQ
虽然三十分钟AK了,但是因为晚开了一个小时,只有四十多名orz
所以这道D题真的是影响深刻,fuko大佬大概开题后3s就口胡完了标算
是非常中(jian)规(jian)中(dan)矩(dan)的D题
下面进入题解:
考虑如果a-b能互换,b-c能互换,那么a-c也一定能互换,这其实可以扔到并查集里,到时候查询a[i]的位置与i是不是祖先相同就可以了(没错就是这么短)
代码如下:
#include<set> #include<cmath> #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> using namespace std; int n,m,a[100010],ans; struct dsu { int fa[200010],rank[200010]; void init(int n) { for(int i=1;i<=n;i++) { fa[i]=i; } } int find(int x) { if(fa[x]==x) { return x; } return fa[x]=find(fa[x]); } void union_(int x,int y) { int fx=find(x); int fy=find(y); if(fx==fy) { return ; } if(rank[fx]<rank[fy]) { fa[fx]=fy; } else { fa[fy]=fx; if(rank[fx]==rank[fy]) { rank[x]++; } } } int same(int x,int y) { return find(x)==find(y); } }b; int main() { cin>>n>>m; b.init(n); for(int i=1;i<=n;i++) { scanf("%d",&a[i]); } for(int i=1;i<=m;i++) { int from,to; scanf("%d%d",&from,&to); b.union_(from,to); } for(int i=1;i<=n;i++) { if(b.same(a[i],i)) { ans++; } } printf("%d ",ans); }
啊,为什么3-1这么水……
以上是关于XJOI 3578 排列交换/AtCoder beginner contest 097D equal (并查集)的主要内容,如果未能解决你的问题,请参考以下文章
AtCoder Beginner Contest 247 EX(推式子)
AtCoder ABC 131F Must Be Rectangular!
AtCoder Grand Contest 002 (AGC002) F - Leftmost Ball 动态规划 排列组合
AtCoder Grand Contest 023 C - Painting Machines
AtCoder Regular Contest (ARC102) E - Stop. Otherwise... 排列组合 动态规划