hdu 3536【并查集】

hdu 3536

题意:

  有N个珠子,第i个珠子初始放在第i个城市。有两种操作: T A B:把A珠子所在城市的所有珠子放到B城市。  Q A:输出A珠子所在城市编号,该城市有多少个珠子,该珠子转移了多少回。

题解:

  在基本并查集的基础上需要两个数组,cnt[i]记录第i个珠子所在城市总共有多少个珠子,tans[i]记录第i个珠子转移了多少回。我开始想的是有T操作是我就把tans[A]++。其实这个是存在问题的,如果A B在同一个城市,其实是不需要转移的。后来我又不怎么明白,为什么要在Find()里面更新tans[]。后来想想,有点明白了。拿样例举例: N=3   1 2 3 。当1的父节点连接2时,tans[1]=1,之后再合并 1,3时,是先找1的父节点2,2直接连到3上,此时是把tans[2]++,因此当查询1所在城市有多少个珠子时,需要tans[1]加上它父亲节点的tans[]。这是一个递归的过程。

  

 1 #include<iostream>
 2 #include<cstdio>
 3 using namespace std;
 4 const int maxn=1e4+50;
 5 int f[maxn],cnt[maxn],tans[maxn];
 6 
 7 void Init(int n)
 8 {
 9     for(int i=1;i<=n;i++){
10         f[i]=i;cnt[i]=1;tans[i]=0;//初始时第i个珠子在第i个城市
11     }
12 }
13 
14 int Find(int x)
15 {
16     if(x==f[x]) return x;
17     int t=f[x];
18     f[x]=Find(f[x]);
19     tans[x]+=tans[t];
20     return f[x];
21 }
22 
23 void Union(int a,int b)
24 {
25     int x=Find(a),y=Find(b);
26     if(x==y) return;
27     f[x]=y;
28     cnt[y]+=cnt[x];
29     tans[x]++;
30 }
31 
32 int main()
33 {
34     int T,N,Q,a,b;
35     char ch;
36     scanf("%d",&T);
37     for(int cas=1;cas<=T;cas++)
38     {
39         printf("Case %d:\n",cas);
40         scanf("%d%d",&N,&Q);
41         Init(N);
42         while(Q--)
43         {
44             scanf(" %c",&ch);
45             if(ch=='T'){
46                 scanf("%d%d",&a,&b);
47                 Union(a,b);
48             }else{
49                 scanf("%d",&a);
50                 int t=Find(a);
51                 printf("%d %d %d\n",t,cnt[t],tans[a]);//cnt[]输出的根节点的
52             }
53         }
54     }
55     return 0;
56 }
View Code

 

posted @ 2018-05-12 10:46  ╰追憶似水年華ぃ╮  阅读(141)  评论(0编辑  收藏  举报