Union Find木(ATC B問題)
ABC065 D - Built?を解く→(((ง ・ө・ )ว?ワカランチン→解説「最小全域木はご存知ですよね」→*1cout << "Yes" << endl; else cout << "No" << endl; } } }
*1:;゚Д゚)オレシラナイシラナイ→最小全域木の解説「閉路の判定にはUnion-Find木を用いると良いです」→Union-Find木って😩💭ナンャ‥‥。
というわけで、Union-Find木から勉強します
問題
以下ネタバレ注意
- const int MAX = 100010;
- int par[MAX];//親
- int Rank[MAX];//木の深さ
- //n要素で初期化
- void init(int n) {
- REP(i, n) {
- par[i] = i;
- Rank[i] = 0;
- }
- }
- //木の根を求める
- int find(int x) {
- if (par[x] == x) {
- return x;
- }
- else {
- return par[x] = find(par[x]);//経路圧縮(根に直接つなぎなおす)もしつつ
- }
- }
- //xとyの属する集合を併合
- void unite(int x, int y) {
- x = find(x);
- y = find(y);
- if (x == y)return;
- //低いほうを高いほうにつなげる(効率化)
- if (Rank[x] < Rank[y]) {
- par[x] = y;
- }
- else {
- par[y] = x;
- if (Rank[x] == Rank[y])Rank[x]++;
- }
- }
- //xとyが同じ集合に属するか否か
- bool same(int x, int y) {
- return find(x) == find(y);
- }
- int N, Q;
- int P[200010], A[200010], B[200010];
- int main() {
- cin >> N >> Q;
- init(N);
- REP(i, Q) {
- cin >> P[i] >> A[i] >> B[i];
- }
- REP(i, Q) {
- //連結クエリ
- if (P[i] == 0) {
- unite(A[i], B[i]);
- }
- //判定クエリ
- if (P[i] == 1) {
- if (same(A[i], B[i]