题目链接:点击打开链接
题目大意:给一个长度为n的序列,下标1~n,然后给m个可以进行的两个数换位置的操作,当然也可以选择不操作,然后问你操作之后最多能得到多少个number:一个数的位置下标正好等于它本身的值
解题思路,一种操作可以被进行无数次,那么我们就可以把能进行交换的数建成一个连通图,用并查集就能很好的判断出一个数能否与它的下标相匹配。
代码:
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<string> #include<map> #include<set> #include<vector> #define FAST ios::sync_with_stdio(false) typedef long long ll; const int inf = 0x3f3f3f3f; const int mod = (int)1e9 + 7; const int maxn = (int)1e5 + 5; using namespace std; int pre[maxn], p[maxn], pos[maxn]; int find(int x){ int r = x; while(pre[r] != r) r = pre[r]; int i = x, t; while(i != r){ t = pre[i]; pre[i] = r; i = t; } return r; } void join(int x, int y){ int fx = find(x), fy = find(y); if(fx != fy) pre[fx] = fy; } int main() { int n, m; scanf("%d %d", &n, &m); for(int i = 1; i <= n; i++) scanf("%d", p + i), pre[i] = i, pos[p[i]] = i; for(int i = 1; i <= m; i++){ int x, y; scanf("%d %d", &x, &y); join(x, y); } for(int i = 1; i <= n; i++) find(i); int ans = 0; for(int i = 1; i <= n; i++){ if(pre[i] == pre[pos[i]]) ans++; } printf("%d\n", ans); return 0; }
over