带权并查集
两道题合起来,说清楚并查集的作用有哪些
连通、集合最值、集合元素个数、到根的距离...
#include<bits/stdc++.h>
using namespace std;
/*查找、合并|统计集合个数、集合最大值、每个集合的元素个数、到根的距离*/
const int maxn = 1e6+10;
int n,m;
int father[maxn];
int size[maxn];//集合中元素的个数
int maxs[maxn];//集合中最大值
int dist[maxn];//到根节点的距离
int setNums = 0;
void init(){
for(int i=1;i<=n;i++){
father[i] = i;
size[i] = 1;
maxs[i] = i;
dist[i] = 0;
}
}
//find循环写法
int Find(int x){
int p,tmp;
p = x;
while(father[x] != x){
x = father[x];//找到祖先节点
}
while(p!=x){//更新p(原x)的父辈节点 的父辈为祖先(x)
tmp = father[p];
father[p] = x;
p = tmp;
}
return x;
}
//递归写法
int find(int x){
if(father[x] == x){
return x;
}
int y = father[x];
father[x] = find(y);
dist[x] += dist[y];//更新x到根节点的距离
return father[x];
}
//合并
void join(int x,int y){
int a = find(x);
int b = find(y);
if(a!=b){
father[a] = b;
dist[a] = size[b];//更新子集合的根到 父集合根 的距离
size[b] += size[a];//更新父亲集合的元素个数
maxs[b] = max(maxs[a],maxs[b]);
}
}
int main(){
cin>>n>>m;//元素数 操作数
init();
char ins[20];
setNums = n;
for(int i=0;i<m;i++){
int x,y;
scanf("%s",ins);
if(ins[0] == 'u'){
cin>>x>>y;
if(find(x) != find(y)){
join(x,y);//合并
setNums--;//合并一次 集合数-1
}
}else if(ins[0] == 's' && ins[1] == 'a'){
cin>>x>>y;
int fx = find(x);
int fy = find(y);//查找是否连接 (在同一集合)
if(fx==fy) cout<<1<<endl;
else cout<<0<<endl;
}else if(ins[0] == 'n'){
cin>>x;
cout<<size[find(x)]<<endl;//查询当前集合中元素的数量
}else if(ins[0] == 'm'){
cin>>x;
cout<<maxs[find(x)]<<endl;//查询当前集合中的最大值
}else if(ins[0] == 's' && ins[1] =='e'){
cout<<setNums<<endl;//查询 集合总数
}else{
cin>>x;
find(x);
cout<<dist[x]<<endl;//打印x到它的集合的根 的距离
// cout<<size[x]-1-dist[x]<<endl;//查询排(与根的距离)在与x同一集合中 x后的有多少人
}
}
return 0;
}