hdu-2818/POJ-1988 Building Block(并查集+路径压缩)

Building Block

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4430    Accepted Submission(s): 1373


Problem Description
John are playing with blocks. There are N blocks (1 <= N <= 30000) numbered 1...N。Initially, there are N piles, and each pile contains one block. Then John do some operations P times (1 <= P <= 1000000). There are two kinds of operation:

M X Y : Put the whole pile containing block X up to the pile containing Y. If X and Y are in the same pile, just ignore this command.
C X : Count the number of blocks under block X

You are request to find out the output for each C operation.
 

Input
The first line contains integer P. Then P lines follow, each of which contain an operation describe above.
 

Output
Output the count for each C operations in one line.
 

Sample Input
  
  
6 M 1 6 C 1 M 2 4 M 2 6 C 3 C 4
 

Sample Output
  
  
1 0

2

题意+思路参考别人:进行m次操作,M x y 将包含x的集合移动到y上面,C x, 计算x下面有几个元素。用p[x]表示x的根结点,

cnt[x]表示x所在集合的元素个数,top[x]表示x上面有几个元素。每次进行路径压缩时,top[x]都要加上

top[p[x]],cnt和p的操作就是并查集的基本操作。最后计算结果是用x所在集合元素的个数 - 在它之上

的个数 - 它本身。

代码:

#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; #define N 30010 int pre[N]; int s[N]; int top[N]; int finds(int x) {     int t;     if(x!=pre[x])     {         t=pre[x];         pre[x]=finds(pre[x]);         top[x]+=top[t];     }     return pre[x]; } void mix(int a,int b) {     int x=finds(a),y=finds(b);     if(x!=y)     {         pre[y]=x;         top[y]=s[x];         s[x]+=s[y];     } } int main() {     int T;     scanf("%d",&T);         char op[2];         int x,y;         for(int i=1;i<=N;i++)             {                 pre[i]=i;                 top[i]=0;                 s[i]=1;             }         while(T--)         {             scanf("%s",op);             if(op[0]=='M')             {                 scanf("%d %d",&x,&y);                 mix(x,y);             }             else             {                 scanf("%d",&x);                 int nx=finds(x);                 printf("%d\n",s[nx]-top[x]-1);             }         }     return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值