P3367 【模板】并查集
题目背景
本题数据范围已经更新到 1≤N≤2×1051\le N\le 2\times 10^51≤N≤2×105,1≤M≤1061\le M\le 10^61≤M≤106。
题目描述
如题,现在有一个并查集,你需要完成合并和查询操作。
输入格式
第一行包含两个整数 N,MN,MN,M ,表示共有 NNN 个元素和 MMM 个操作。
接下来 MMM 行,每行包含三个整数 Zi,Xi,YiZ_i,X_i,Y_iZi,Xi,Yi 。
当 Zi=1Z_i=1Zi=1 时,将 XiX_iXi 与 YiY_iYi 所在的集合合并。
当 Zi=2Z_i=2Zi=2 时,输出 XiX_iXi 与 YiY_iYi 是否在同一集合内,是的输出
Y
;否则输出 N
。
输出格式
对于每一个 Zi=2Z_i=2Zi=2 的操作,都有一行输出,每行包含一个大写字母,为 Y
或者 N
。
输入输出样例 #1
输入 #1
4 7
2 1 2
1 1 2
2 1 2
1 3 4
2 1 4
1 2 3
2 1 4
输出 #1
N
Y
N
Y
说明/提示
对于 15%15\%15% 的数据,N≤10N \le 10N≤10,M≤20M \le 20M≤20。
对于 35%35\%35% 的数据,N≤100N \le 100N≤100,M≤103M \le 10^3M≤103。
对于 50%50\%50% 的数据,1≤N≤1041\le N \le 10^41≤N≤104,1≤M≤2×1051\le M \le 2\times 10^51≤M≤2×105。
对于 100%100\%100% 的数据,1≤N≤2×1051\le N\le 2\times 10^51≤N≤2×105,1≤M≤1061\le M\le 10^61≤M≤106,1≤Xi,Yi≤N1 \le X_i, Y_i \le N1≤Xi,Yi≤N,Zi∈{1,2}Z_i \in \{ 1, 2 \}Zi∈{1,2}。
代码
并查集模板
数据结构
parent[i]
:记录结点i的父结点rank[i]
:以i为根的集合的高度
初始化
void init(){for(int i=1;i<=n;i++){Rank[i]=1;parent[i]=i;}
}
查询
int find(int x){if(parent[x]!=x)parent[x]=find(parent[x]);return parent[x];
}
合并
void Union(int x,int y){int rootx=find(x);int rooty=find(y);if(rootx==rooty)return;if(Rank[rootx]>Rank[rooty]){parent[rooty]=rootx;}else if(Rank[rootx]<Rank[rooty]){parent[rootx]=rooty;}else{parent[rooty]=rootx;Rank[rootx]++;}
}
完整代码
#include<bits/stdc++.h>
using namespace std;
int n, m;
int parent[200005];
int Rank[200005];
void init(){for(int i=1;i<=n;i++){Rank[i]=1;parent[i]=i;}
}
int find(int x){if(parent[x]!=x)parent[x]=find(parent[x]);return parent[x];
}
void Union(int x,int y){int rootx=find(x);int rooty=find(y);if(rootx==rooty)return;if(Rank[rootx]>Rank[rooty]){parent[rooty]=rootx;}else if(Rank[rootx]<Rank[rooty]){parent[rootx]=rooty;}else{parent[rooty]=rootx;Rank[rootx]++;}
}
int main(){cin>>n>>m;init();int x,y,z;for(int i=0;i<m;i++){cin>>z>>x>>y;if(z==1){Union(x, y);}else{if(find(x)==find(y))cout<<"Y"<<endl;elsecout<<"N"<<endl;}}return 0;
}