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
 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 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 }