当前位置: 代码迷 >> 综合 >> 【HDU 2818】 Building Block 【带权并查集】
  详细解决方案

【HDU 2818】 Building Block 【带权并查集】

热度:54   发布时间:2023-11-10 02:10:22.0

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

分析:想了许久,终于a了。
建议本题 自己仔细想想 再看题解,自己想通之后 你会对带权并查集有个更加清晰的理解。
对于基础的并查集 你需要知道 :用pre[]和Rank[] 可以很好的动态维护任何一个点属于哪个集合,和每个集合有几个元素。
刚想本题的时候,你会发现有两个值不好维护 。
第一个 : 对于M 操作,你如何快速的判断x和y分别在哪个盘子上? 只是这一个问题的话,很好解决,用一个并查集就足够。
第二个问题: 对于C操作,你如何快速的判断其下方有几个物体。我们可以试着用上一个问题的思路来想 ,现在有一个并查集来维护,我们可以快速的知道C是属于哪个盘子的,但是其下方的值呢? 。 这里是最不好想的一个地方,这个问题的话,你需要自己多模拟几遍这个游戏的过程,看懂这个M操作会对C操作有什么影响。 很快你就会发现,对于M x y (x的盘子tx,y的盘子ty)会导致 tx 上的所有物品 其下方所放物品的数目都会加上 ty盘子上所有物品的数目。看懂这一点之后 就是带权并查集的用处了,relation[i] 代表i 和pre[i]之间有几个物品。然后我们 路径压缩的时候,就可以得到每个物品对于 集合代表元素的 物品差 。
代码

#include<cstring>
#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
#define LL long longconst int N = 30000+11 ;
const int M = 1e6;
const int mod = 7653;
const int inf = 0x3f3f3f3f;int pre[N],relation[N],Rank[N];
void init(){for(int i=0;i<N;i++){pre[i]=i;relation[i]=0;Rank[i]=1;}
}int Find(int x){if(x==pre[x]) return x;int t=pre[x];pre[x]=Find(pre[x]);relation[x]= relation[x]+relation[t]; // 路径压缩 return pre[x];
}
void Join(int x,int y){int tx=Find(x); int ty=Find(y);if(tx!=ty){relation[tx]+=Rank[ty];Rank[ty]+=Rank[tx]; pre[tx]=ty;}
}
int main(){int n,m;while(scanf("%d",&m)!=EOF){init();while(m--){char s[5];scanf("%s",s);if(s[0]=='M'){int a,b;scanf("%d%d",&a,&b);Join(a,b);}else if(s[0]=='C'){int x; scanf("%d",&x);Find(x); // 这里注意,一定要路径压缩一下 printf("%d\n",relation[x]);}}}
return 0;
}
  相关解决方案