Codeforces--Books Exchange (hard version)
题目链接http://codeforces.com/contest/1249/problem/B2 。并查集思想,将数分成多个集合,每个集合的大小就是一轮的所需天数。
Map[i]存储数据。
flag[i]来表示第i个数是否被访问过。
mm[i]记录第i个集合所对应的集合大小,索引i为第i个集合的根对应的值。
getParent方法利用递归的思想更新每个节点的上继,直接指向当前集合的根。
由于访问过的集合不再进行访问,因此,分析时间复杂度,准确是O(CN),C为一个常数。在这里需要注意的是,mm在每次使用后要清,不然会有问题。
1 #include<bits/stdc++.h> 2 3 /* 4 * 并查集 5 */ 6 7 using namespace std; 8 9 static const int MAX = 200005; 10 11 int Map[MAX]; 12 bool flag[MAX]; 13 map<int, int> mm; 14 15 int getParent(int x){ 16 if(!flag[x]){ 17 flag[x] = true; 18 Map[x] = getParent(Map[x]); 19 } 20 return Map[x]; 21 } 22 23 int main(){ 24 int q; 25 scanf("%d", &q); 26 while(q--){ 27 int n; 28 scanf("%d", &n); 29 for(int i=1;i<=n;i++){ 30 flag[i] = false; 31 } 32 33 // construct set 34 int tmp; 35 for(int i=1;i<=n;i++){ 36 scanf("%d", &Map[i]); 37 } 38 39 // solve 40 for(int i=1;i<=n;i++){ 41 int parent = getParent(i); 42 mm[parent]++; 43 } 44 45 for(int i=1;i<=n;i++){ 46 if(i==1){ 47 printf("%d", mm[Map[i]]); 48 } 49 else{ 50 printf(" %d", mm[Map[i]]); 51 } 52 } 53 printf("\n"); 54 mm.clear(); 55 } 56 return 0; 57 }