Problem:
Disjoint Set
Write a program which manipulates a disjoint set
S = {S
1
, S
2
, . . . , S
k
}
.
First of all, the program should read an integer
n
, then make a disjoint set where each element consists of 0, 1, ...
n−1
respectively.
Next, the program should read an integer
q
and manipulate the set for
q
queries. There are two kinds of queries for different operations:
unite(x, y)
: unites sets that contain
x
and
y
, say
S
x
and
S
y
, into a new set.
same(x, y)
: determine whether
x
and
y
are in the same set.
Input
n
q
com
1
x
1
y
1
com
2
x
2
y
2
...
com
q
x
q
y
q
In the first line,
n
and
q
are given. Then,
q
queries are given where
com
represents the type of queries. '0' denotes
unite
and '1' denotes
same
operation.
Output
For each
same
operation, print
1
if
x
and
y
are in the same set, otherwise
0
, in a line.
Constraints
1 ≤ n ≤ 10000
1 ≤ q ≤ 100000
x ≠ y
Sample Input
5 12
0 1 4
0 2 3
1 1 2
1 3 4
1 1 4
1 3 2
0 1 3
1 2 4
1 3 0
0 0 4
1 0 2
1 3 0
Sample Output
0
0
1
1
1
0
1
1

Submitted solutions:

code_snippet: #include <iostream>
#include <vector>
#include <cstdint>

namespace uft { // mst.cc で merge 関数を使用するために、名前空間を定義する

uint16_t root(uint16_t idx, std::vector<uint16_t>& parent) {
    if (parent[idx] == idx) { // 親が自分自身の場合
        return idx;
    }
    return (parent[idx] = root(parent[idx], parent)); // 親が自分自身でない場合は、再帰的に root を更新する (経路を圧縮する)
}

bool same_root(uint16_t i_1, uint16_t i_2, std::vector<uint16_t>& parent) { // i_1 と i_2 が同じグラフに所属するかどうか
    return root(i_1, parent) == root(i_2, parent);
}

void merge(uint16_t i_1, uint16_t i_2, std::vector<uint16_t>& parent) {
    parent[root(i_1, parent)] = root(i_2, parent); // i_1 のルートノードを i_2 のルートノードにする
}
}

#ifndef NO_MAIN

uint16_t n; // 要素の数
uint q; // クエリの数

int main() {
    using namespace uft;

    std::cin >> n >> q;

    std::vector<uint16_t> parent;

    parent.resize(n+1); // n 個の要素のためのメモリを確保する

    parent[0] = 0; // 番兵ノード

    // n 個のグラフを作成する (すべての要素は、親が自分自身、つまり root であると初期化される)
    for (uint16_t i = 1; i < n+1; ++i) {
        parent[i] = i;
    }

    std::vector<uint16_t> qry; // クエリ設定を保存するベクタ
    qry.resize(3); // 要素を 3 つ確保しておく

    // 各クエリ順に、グラフの統合、親ノードの同一性の判定を行う
    for (uint i = 0; i < q; ++i) {
        std::cin >> qry[0] >> qry[1] >> qry[2];

        if (qry[0] == 0) { // unite クエリの場合
            merge(qry[1], qry[2], parent); // マージする
        } else { // same クエリの場合
            if (same_root(qry[1], qry[2], parent)) {
               std::cout << 1 << "\n";
            } else {
                std::cout << 0 << "\n";
            }
        }
    }
}
#endif
accuracy: 1
time_ms: 70
memory_kb: 3584
final_rank: 18

code_snippet: #include <iostream>
#include <vector>
using namespace std;

vector<int> parent, rankv;

int root(int x) {
    if (parent[x] == x) return x;
    return parent[x] = root(parent[x]);
}

bool same(int x, int y) {
    return root(x) == root(y);
}

void unite(int a, int b) {
    a = root(a);
    b = root(b);
    if (a == b) return;
    if (rankv[a] < rankv[b]) swap(a, b); //ランクが小さい方を常にbにする
    parent[b] = a;
    if (rankv[a] == rankv[b]) ++rankv[a];
}

int main() {
    int n, q;
    cin >> n >> q;
    parent.assign(n, 0);
    rankv.assign(n, 0);
    for (int i = 0; i < n; ++i) parent[i] = i;

    for (int i = 0; i < q; ++i) {
        int k, x, y;
        cin >> k >> x >> y;
        if (k == 0) {
            unite(x, y);
        } else {
            cout << (same(x, y) ? 1 : 0) << endl;
        }
    }

    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 3524
final_rank: 11

code_snippet: #include <iostream>
using namespace std;

int P[10010];
void init(int N){
    for(int i=0; i<N; ++i) P[i] = i;
}
int root(int a) {
    if (P[a] == a) return a;
    return (P[a] = root(P[a]));
}
bool same(int a, int b) {
    return root(a) == root(b);
}
void unite(int a, int b) {
    P[root(a)] = root(b);
}

int main() {
    int n;
    cin >> n;
    init(n);

    int q;
    cin >> q;
    for(int i=0; i<q; ++i) {
        int com, x, y;
        cin >> com >> x >> y;
        if (com==0) unite(x, y);
        else cout << same(x, y) << endl;
    }
}
accuracy: 1
time_ms: 60
memory_kb: 3456
final_rank: 6

code_snippet: #include <iostream>
#include <cassert>
#include <vector>
using namespace std;

class unionfind{
public:
    unionfind(int n): n_(n) {
        parent_.resize(n);
        size_.resize(n);
        for(int i=0; i<n; i++){
            parent_[i] = i;
            size_[i] = 1;
        }
    }
    int root(int i){
        if(parent_[i] == i) return i;
        parent_[i] = root(parent_[i]);
        return parent_[i];
    }
    void unite(int i, int j){
        int p = root(i);
        int q = root(j);
        if(p==q) return;
        if(size_[p]>size_[q]){
            parent_[q] = p;
            size_[p] += size_[q];
        }else{
            parent_[p] = q;
            size_[q] += size_[p];
        }
    }
    bool is_same(int i, int j){
        return root(i) == root(j);
    }
private:
    int n_;
    vector<int> parent_;
    vector<int> size_;
};

int main(){
    int n,q;
    cin >> n >> q;

    unionfind uf(n+5);
    int com,x,y;
    for(int i=0; i<q; i++){
        cin >> com >> x >> y;
        if(com == 0){
            uf.unite(x,y);
        }else{
            cout << (int)uf.is_same(x,y) << endl;
        }
    }
}
accuracy: 1
time_ms: 60
memory_kb: 3500
final_rank: 8

code_snippet: #include <iostream>
#include <string>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cctype>
#include <cstdarg>
#include <cstddef>
#include <cstdint>
#include <cstdbool>
#include <cstdint>
using namespace std;

int P[10010]; // 0 から 10000 までの頂点を取り扱い可能 
void init(int N) { // 初期化 はじめは全ての頂点はバラバラ 
    for (int i=0; i<=N; ++i) P[i] = i; 
} 
int root(int a) { // a の root(代表元) を求める 
    if (P[a] == a) return a; // a は root 
    return (P[a] = root(P[a])); // a の親の root を求め,a の親とする 
} 
bool is_same_set(int a, int b) { // a と b が同じグループに属するか? 
    return root(a) == root(b); 
} 
void unite(int a, int b) { // a と b を同一グループにまとめる 
    P[root(a)] = root(b); 
}

int main() {
    int n, q;
    cin >> n >> q;
    init(n);
    for (int i = 0; i < q; i++) {
        int com, x, y;
        cin >> com >> x >> y;
        if (com == 0) {
            unite(x, y);
        } else {
            cout << (is_same_set(x, y) ? 1 : 0) << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 70
memory_kb: 3476
final_rank: 14

code_snippet: #include <iostream>
#include <vector>
#include <cstdint>

uint16_t n; // 要素の数
uint q; // クエリの数

namespace uft { // mst.cc で merge 関数を使用するために、名前空間を定義する
std::vector<uint16_t> parent; // 親のノードの値を積んだベクタ

uint16_t root(uint16_t idx) {
    if (parent[idx] == idx) { // 親が自分自身の場合
        return idx;
    }
    return (parent[idx] = root(parent[idx])); // 親が自分自身でない場合は、再帰的に root を更新する (経路を圧縮する)
}

bool same_root(uint16_t i_1, uint16_t i_2) { // i_1 と i_2 が同じグラフに所属するかどうか
    return root(i_1) == root(i_2);
}

void merge(uint16_t i_1, uint16_t i_2) {
    parent[root(i_1)] = root(i_2); // i_1 のルートノードを i_2 のルートノードにする
}
}

#ifndef NO_MAIN
int main() {
    using namespace uft;

    std::cin >> n >> q;

    parent.resize(n+1); // n 個の要素のためのメモリを確保する

    parent[0] = 0; // 番兵ノード

    // n 個のグラフを作成する (すべての要素は、親が自分自身、つまり root であると初期化される)
    for (uint16_t i = 1; i < n+1; ++i) {
        parent[i] = i;
    }

    std::vector<uint16_t> qry; // クエリ設定を保存するベクタ
    qry.resize(3); // 要素を 3 つ確保しておく

    // 各クエリ順に、グラフの統合、親ノードの同一性の判定を行う
    for (uint i = 0; i < q; ++i) {
        std::cin >> qry[0] >> qry[1] >> qry[2];

        if (qry[0] == 0) { // unite クエリの場合
            merge(qry[1], qry[2]); // マージする
        } else { // same クエリの場合
            if (same_root(qry[1], qry[2])) {
               std::cout << 1 << "\n"; 
            } else {
                std::cout << 0 << "\n";
            }
        }
    }
}
#endif
accuracy: 1
time_ms: 60
memory_kb: 3460
final_rank: 7

code_snippet: #include <iostream>
#include <vector>
#include <cstdint>

uint16_t n; // 要素の数
uint q; // クエリの数

namespace uft { // mst.cc で merge 関数を使用するために、名前空間を定義する
std::vector<uint16_t> parent; // 親のノードの値を積んだベクタ

uint16_t root(uint16_t idx) {
    if (parent[idx] == idx) { // 親が自分自身の場合
        return idx;
    }
    return (parent[idx] = root(parent[idx])); // 親が自分自身でない場合は、再帰的に root を更新する (経路を圧縮する)
}

bool same_root(uint16_t i_1, uint16_t i_2) { // i_1 と i_2 が同じグラフに所属するかどうか
    return root(i_1) == root(i_2);
}

void merge(uint16_t i_1, uint16_t i_2) {
    parent[root(i_1)] = root(i_2); // i_1 のルートノードを i_2 のルートノードにする
}
}
int main() {
    using namespace uft;

    std::cin >> n >> q;

    parent.resize(n+1); // n 個の要素のためのメモリを確保する

    parent[0] = 0; // 番兵ノード

    // n 個のグラフを作成する (すべての要素は、親が自分自身、つまり root であると初期化される)
    for (uint16_t i = 1; i < n+1; ++i) {
        parent[i] = i;
    }

    std::vector<uint16_t> qry; // クエリ設定を保存するベクタ
    qry.resize(3); // 要素を 3 つ確保しておく

    // 各クエリ順に、グラフの統合、親ノードの同一性の判定を行う
    for (uint i = 0; i < q; ++i) {
        std::cin >> qry[0] >> qry[1] >> qry[2];

        if (qry[0] == 0) { // unite クエリの場合
            merge(qry[1], qry[2]); // マージする
        } else { // same クエリの場合
            if (same_root(qry[1], qry[2])) {
               std::cout << 1 << "\n"; 
            } else {
                std::cout << 0 << "\n";
            }
        }
    }
}
accuracy: 1
time_ms: 70
memory_kb: 3460
final_rank: 13

code_snippet: #include <iostream>
#include <vector>
#include <cstdint>

uint16_t n; // 要素の数
uint q; // クエリの数

std::vector<uint16_t> parent; // 親のノードの値を積んだベクタ

uint16_t root(uint16_t idx) {
    if (parent[idx] == idx) { // 親が自分自身の場合
        return idx;
    }
    return (parent[idx] = root(parent[idx])); // 親が自分自身でない場合は、再帰的に root を更新する (経路を圧縮する)
}

bool same_root(uint16_t i_1, uint16_t i_2) { // i_1 と i_2 が同じグラフに所属するかどうか
    return root(i_1) == root(i_2);
}

void merge(uint16_t i_1, uint16_t i_2) {
    parent[root(i_1)] = root(i_2); // i_1 のルートノードを i_2 のルートノードにする
}

int main() {
    std::cin >> n >> q;

    parent.resize(n+1); // n 個の要素のためのメモリを確保する

    parent[0] = 0; // 番兵ノード

    // n 個のグラフを作成する (すべての要素は、親が自分自身、つまり root であると初期化される)
    for (uint16_t i = 1; i < n+1; ++i) {
        parent[i] = i;
    }

    std::vector<uint16_t> qry; // クエリ設定を保存するベクタ
    qry.resize(3); // 要素を 3 つ確保しておく

    // 各クエリ順に、グラフの統合、親ノードの同一性の判定を行う
    for (uint i = 0; i < q; ++i) {
        std::cin >> qry[0] >> qry[1] >> qry[2];

        if (qry[0] == 0) { // unite クエリの場合
            merge(qry[1], qry[2]); // マージする
        } else { // same クエリの場合
            if (same_root(qry[1], qry[2])) {
               std::cout << 1 << "\n"; 
            } else {
                std::cout << 0 << "\n";
            }
        }
    }
}
accuracy: 1
time_ms: 70
memory_kb: 3504
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define v vector
using vi = v<int>;
using vl = v<ll>;
using vs = v<string>;
#define rep(i, n) for (ll i = 0; i < (ll)(n); i++)
#define rRep(i, n) for (ll i = (ll)(n); i >= 0; i--)
#define all(vec) vec.begin(), vec.end()
#define rAll(vec) vec.rbegin(), vec.rend()
// 昇順(小さい→大きい)
#define vSort(vec) sort(all(vec))
#define rSort(vec) sort(rAll(vec))
// sortしてから使う
#define uni(vec) vec.erase(unique(all(vec)), vec.end());

// ここから追加
const int intMax = INT_MAX;
const ll llMax = LONG_LONG_MAX;
const ll INF = 1e18;
template<class T> inline bool chmax(T& a, T b) { if (a < b) { a = b; return true; } return false; }
template<class T> inline bool chmin(T& a, T b) { if (a > b) { a = b; return true; } return false; }
template <typename T> T gcd(T a, T b) {if (b == 0) return a; else return gcd(b, a % b);}
template <typename T> inline T lcm(T a, T b) { return (a / gcd(a, b) * b); }
#define coutFloat(N) cout << fixed << setprecision(N)

struct UnionFind {
    vector<int> par, rank, siz;

    // 構造体の初期化
    UnionFind(int n) : par(n,-1), rank(n,0), siz(n,1) { }

    // 根を求める
    int root(int x) {
        if (par[x]==-1) return x; // x が根の場合は x を返す
        else return par[x] = root(par[x]); // 経路圧縮
    }

    // x と y が同じグループに属するか (= 根が一致するか)
    bool issame(int x, int y) {
        return root(x)==root(y);
    }

    // x を含むグループと y を含むグループを併合する
    bool unite(int x, int y) {
        int rx = root(x), ry = root(y); // x 側と y 側の根を取得する
        if (rx==ry) return false; // すでに同じグループのときは何もしない
        // union by rank
        if (rank[rx]<rank[ry]) swap(rx, ry); // ry 側の rank が小さくなるようにする
        par[ry] = rx; // ry を rx の子とする
        if (rank[rx]==rank[ry]) rank[rx]++; // rx 側の rank を調整する
        siz[rx] += siz[ry]; // rx 側の siz を調整する
        return true;
    }

    // x を含む根付き木のサイズを求める
    int size(int x) {
        return siz[root(x)];
    }
};

int main() {
  int N, Q; cin >> N >> Q;

  UnionFind uf = UnionFind(N);
  rep(_, Q) {
    int cmd, x, y; cin >> cmd >> x >> y;
    if (cmd == 0) {
      // unite
      uf.unite(x, y);
    } else {
      cout << (int)(uf.issame(x, y)) << endl;
    }
  }

  return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 3560
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;

struct UnionFind {
    vector<int> par, rank, siz;
    UnionFind(int N) : par(N,-1), rank(N,1), siz(N,1) {}

    int root(int x) {
        if (par[x] == -1) return x;
        else return par[x] = root(par[x]);
    }

    void unite(int x, int y) {
        int rx = root(x), ry = root(y);
        if (rx == ry) return;
        if (rank[rx] < rank[ry]) swap(rx, ry);

        par[ry] = rx;
        siz[rx] += siz[ry];
        if (rank[rx] == rank[ry]) rank[rx]++;
    }
};

int main() {
    int N, Q;
    cin >> N >> Q;

    UnionFind uf(N);
    for (int qi = 0; qi < Q; qi++) {
        int type; cin >> type;
        if (type == 0) {
            int x, y;
            cin >> x >> y;
            uf.unite(x, y);
        } else if (type == 1) {
            int x, y;
            cin >> x >> y;
            if (uf.root(x) == uf.root(y)) cout << 1 << endl;
            else cout << 0 << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 3512
final_rank: 10

code_snippet: #include <bits/stdc++.h>
using namespace std;

const int N = 1e6;
int n, q;
int par[N];
int area[N];

int getpar(int u) {
  if (par[u] == u)
    return u;

  return par[u] = getpar(par[u]);
}

void merge(int u, int v) {
  int pu = getpar(u), pv = getpar(v);

  if (pu == pv)
    return;

  if (area[pu] < area[pv])
    swap(pu, pv); // pu > pv

  area[pu] += area[pv];
  par[pv] = pu;
}

bool connected(int u, int v) { return getpar(u) == getpar(v); }

int main() {
  ios::sync_with_stdio(false);
  cin.tie(0);

  cin >> n >> q;

  fill(area, area + n, 1);
  iota(par, par + n, 0);

  while (q--) {
    int a, b;
    char t;
    cin >> t >> a >> b;

    if (t == '0') {
      merge(a, b);
    } else {
      cout << connected(a, b) << '\n';
    }
  }
}
accuracy: 1
time_ms: 10
memory_kb: 5544
final_rank: 19

code_snippet: #include<bits/stdc++.h>
using namespace std;
struct union_find{
	vector<int>d;
	union_find(int n):d(n,-1){}
	int root(int u){return d[u]<0?u:d[u]=root(d[u]);}
	bool unite(int u,int v){
		u=root(u),v=root(v);
		if(u==v)return 0;
		if(d[u]>d[v])swap(u,v);
		d[u]+=d[v];
		d[v]=u;
		return 1;
	}
};
int main(){
	cin.tie(0)->sync_with_stdio(0);
	int n,q;
	cin>>n>>q;
	union_find uf(n);
	while(q--){
		int op,u,v;
		cin>>op>>u>>v;
		if(op==0){
			uf.unite(u,v);
		}
		if(op==1){
			cout<<(uf.root(u)==uf.root(v))<<'\n';
		}
	}
}
accuracy: 1
time_ms: 10
memory_kb: 3480
final_rank: 2

code_snippet: #include <bits/stdc++.h>
#define rep(i,n) for(int i=0;i<(int)(n);++i)
#define revrep(i,n) for(int i=(int)(n)-1;i>=0;--i)
using namespace std;
using ll = long long;

class UnionFind {

private:
    vector<int> parent;
    vector<int> sz;

public:
    UnionFind(int n):parent(n),sz(n,1){
        iota(parent.begin(),parent.end(),0);
    }
    
    int find(int x){
        if(parent[x]==x){ return x;}
        return find(parent[x]);
    }
    
    bool same(int x,int y){
        return (find(x) == find(y));
    }
    
    bool unite(int x,int y){
        int root_x = find(x);
        int root_y = find(y);
        if(root_x!=root_y){
            if(root_x<root_y) swap(root_x,root_y);
            parent[root_y] = root_x;
            sz[root_x] += sz[root_y];
            return true;
        }
        return false;
    }
    
    int size(int x){ return sz[find(x)];}
};


int main(void){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int n,Q;cin>>n>>Q;
    UnionFind S(n);
    
    while(Q--){
        int com;cin>>com;
        if(com==0){
            int x,y;cin>>x>>y;
            S.unite(x,y);
        }else{
            int x,y;cin>>x>>y;
            cout << S.same(x,y) << endl;
        }
    }
    return 0;
}
accuracy: 1
time_ms: 130
memory_kb: 3500
final_rank: 20

code_snippet: #define _USE_MATH_DEFINES
#include<bits/stdc++.h>
#define OVERLOAD_REP(v1, v2, v3, v4, NAME, ...) NAME
#define REP1(i, n) for (int i = 0; (i) < (n); ++(i))
#define REP2(i, l, r) for (int i = (l); (i) < (r); ++(i))
#define REP3(i, l, r, d) for (int i = (l); (i) < (r); (i)+=(d))
#define rep(...) OVERLOAD_REP(__VA_ARGS__, REP3, REP2, REP1)(__VA_ARGS__)
#define OVERLOAD_PRE(v1, v2, v3, v4, NAME, ...) NAME
#define PRE1(i, n) for (int i = (n)-1; (i) >= 0; --(i)) // [0,n)
#define PRE2(i, l, r) for (int i = (r)-1; (i) >= (l); --(i)) //[l,r)
#define PRE3(i, l, r, d) for (int i = (r)-1; (i) >= (l); (i)-=(d))
#define pre(...) OVERLOAD_PRE(__VA_ARGS__, PRE3, PRE2, PRE1)(__VA_ARGS__)
#define bg begin()
#define en end()
#define rbg rbegin()
#define ren rend()
#define all(x) x.bg,x.en
#define rall(x) x.rbg,x.ren
#define pf push_front
#define pb push_back
#define eb emplace_back
#define fir first
#define sec second
#define sz(x) ((int)(x).size())
using namespace std;
using ll = long long;
using ull = unsigned long long;
using ld = long double;
using pii = pair<int,int>;
using pll = pair<ll,ll>;
using sti = stack<int>;
using sei = set<int>;
using qi = queue<int>;
using qii = queue<pii>;
using dqi = deque<int>;
template<class t, class s> using umap = unordered_map<t,s>;
template<class t> using uset = unordered_set<t>;
template<class t> using mset = multiset<t>;
template<class t> using pq=priority_queue<t>;
template<class t> using pqg=priority_queue<t,vector<t>, greater<t>>;
template<class t> using vc=vector<t>;
template<class t> using vvc=vc<vc<t>>;
template<class t> using vvvc=vc<vc<vc<t>>>;
using vi=vc<int>;
using vvi=vc<vc<int>>;
using vll=vc<ll>;
using vvll=vc<vc<ll>>;
using vd=vc<double>;
using vvd=vc<vc<double>>;
using vb=vc<bool>;
using vvb=vc<vc<bool>>;
using vch=vc<char>;
using vs=vc<string>;
const int inf = 1001001001;
const ll infl = 1LL << 60;
const ll mod = 998244353;
template<class t,class u> bool chmax(t&a,u b){if(a<b){a=b; return true;} return false;}
template<class t,class u> bool chmin(t&a,u b){if(a>b){a=b; return true;} return false;}
void yes(){ cout << "Yes" << '\n'; }
void no(){ cout << "No" << '\n'; }

/* UnionFind
    root(x): xの根。O(α(n))
    size(x): x を含む集合の要素数。
    same(x, y): x と y が同じ集合にいるか。O(α(n))
    merge(x, y): x と y を同じ集合にする。 O(α(n))
*/
struct UF{
    vi par;
    UF() {}
    UF(int n): par(n,-1){}
    int root(int x){
        if(par[x] < 0) return x;
        return par[x] = root(par[x]); //経路圧縮
    }
    int size(int x){
        return -par[root(x)];
    }
    bool same(int x, int y){
        return root(x) == root(y);
    }
    bool merge(int x, int y){
        int rx = root(x), ry = root(y);
        if(rx == ry) return false;
        if(-par[rx]<-par[ry]) swap(rx,ry);
        par[rx] += par[ry];
        par[ry] = rx;
        return true;
    }
};

int main(){	
	ios::sync_with_stdio(false);
  	cin.tie(0);
	int n,q; cin >> n >> q;
    UF uf(n);
    rep(i,q){
        int type; cin >> type;
        if(type==0){
            int s,t; cin >> s >> t;
            uf.merge(s,t);
        } else {
            int s,t; cin >> s >> t;
            cout << (uf.same(s,t)? 1 : 0) << endl;
        }
    }
	return 0;
}
accuracy: 1
time_ms: 30
memory_kb: 3480
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using namespace std;
#define rep(i, a, n) for (int i = a; i < n; ++i)
#define rrep(i, a, n) for (int i = n - 1; i >= a; --i)
using ll = long long;
using ld = long double;
using pl = pair<ll, ll>;
using vl = vector<ll>;
using vvl = vector<vl>;
using vp = vector<pl>;
using vvp = vector<vp>;
using vb = vector<bool>;
using vvb = vector<vb>;
using vs = vector<string>;
using vc = vector<char>;
using vvc = vector<vc>;
const int mod = 1000000007;
const ll hashh = 2147483647;

#ifndef ATCODER_DSU_HPP
#define ATCODER_DSU_HPP 1

#include <algorithm>
#include <cassert>
#include <vector>

namespace atcoder
{

    // Implement (union by size) + (path compression)
    // Reference:
    // Zvi Galil and Giuseppe F. Italiano,
    // Data structures and algorithms for disjoint set union problems
    struct dsu
    {
    public:
        dsu() : _n(0) {}
        explicit dsu(int n) : _n(n), parent_or_size(n, -1) {}

        int merge(int a, int b)
        {
            assert(0 <= a && a < _n);
            assert(0 <= b && b < _n);
            int x = leader(a), y = leader(b);
            if (x == y)
                return x;
            if (-parent_or_size[x] < -parent_or_size[y])
                std::swap(x, y);
            parent_or_size[x] += parent_or_size[y];
            parent_or_size[y] = x;
            return x;
        }

        bool same(int a, int b)
        {
            assert(0 <= a && a < _n);
            assert(0 <= b && b < _n);
            return leader(a) == leader(b);
        }

        int leader(int a)
        {
            assert(0 <= a && a < _n);
            return _leader(a);
        }

        int size(int a)
        {
            assert(0 <= a && a < _n);
            return -parent_or_size[leader(a)];
        }

        std::vector<std::vector<int>> groups()
        {
            std::vector<int> leader_buf(_n), group_size(_n);
            for (int i = 0; i < _n; i++)
            {
                leader_buf[i] = leader(i);
                group_size[leader_buf[i]]++;
            }
            std::vector<std::vector<int>> result(_n);
            for (int i = 0; i < _n; i++)
            {
                result[i].reserve(group_size[i]);
            }
            for (int i = 0; i < _n; i++)
            {
                result[leader_buf[i]].push_back(i);
            }
            result.erase(
                std::remove_if(result.begin(), result.end(),
                               [&](const std::vector<int> &v)
                               { return v.empty(); }),
                result.end());
            return result;
        }

    private:
        int _n;
        // root node: -1 * component size
        // otherwise: parent
        std::vector<int> parent_or_size;

        int _leader(int a)
        {
            if (parent_or_size[a] < 0)
                return a;
            return parent_or_size[a] = _leader(parent_or_size[a]);
        }
    };

} // namespace atcoder

#endif // ATCODER_DSU_HPP

using namespace atcoder;

// main
int main()
{
    ll n, q;
    cin >> n >> q;
    dsu d(n);
    rep(i, 0, q)
    {
        ll c, x, y;
        cin >> c >> x >> y;
        if (c == 0)
        {
            d.merge(x, y);
        }
        else
        {
            if (d.same(x, y))
            {
                cout << 1 << endl;
            }
            else
            {
                cout << 0 << endl;
            }
        }
    }
}
accuracy: 1
time_ms: 70
memory_kb: 3480
final_rank: 15

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;






class UnionFind {
    public:
    int par[100009];
    int siz[100009];

    void init(int N) {
        for(int i = 0; i < N; i++) par[i] = -1;
        for(int i = 0; i < N; i++) siz[i] = 1;
    }

    int root(int v) {
        if(par[v] == -1) return v;
        return root(par[v]);
    }

    void unite(int v, int u) {
        int RootV = root(v), RootU = root(u);

        if(root(u) == root(v)) return;

        if(siz[RootV] > siz[RootU]) {
            par[RootU] = RootV;
            siz[RootV] += siz[RootU];
        } else {
            par[RootV] = RootU;
            siz[RootU] += siz[RootV];
        }
    }

    bool same(int v, int u) {
        return root(v) == root(u);
    }
};







int main() {
    int n, q; cin >> n >> q;
    UnionFind UF;
    UF.init(n);

    for(int i = 0; i < q; i++) {
        int cmd; cin >> cmd;
        int x, y; cin >> x >> y;
        if(cmd == 0) {
            UF.unite(x, y);
        } else {
            if(UF.same(x, y)) cout << 1 << endl;
            else cout << 0 << endl;
        }
    }
}
accuracy: 1
time_ms: 60
memory_kb: 3452
final_rank: 5

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;






class UnionFind {
    public:
    int par[10009];
    int siz[10009];

    void init(int n) {
        for(int i = 0; i < n; i++) par[i] = -1;
        for(int i = 0; i < n; i++) siz[i] = 1;
    }

    int root(int x) {
        if(par[x] == -1) return x;
        return root(par[x]);
    }

    void unite(int v, int u) {
        int rootV = root(v);
        int rootU = root(u);

        if(rootV == rootU) return;
        if(siz[rootV] < siz[rootU]) {
            par[rootV] = rootU;
            siz[rootU] += siz[rootV];
        } else {
            par[rootU] = rootV;
            siz[rootV] += siz[rootU];
        }
    }

    bool same(int v, int u) {
        return root(v) == root(u);
    }
};







int main() {
    int n, q; cin >> n >> q;
    UnionFind UF;
    UF.init(n);

    for(int i = 0; i < q; i++) {
        int x, u, v; cin >> x >> u >> v;
        if(x == 0) UF.unite(u, v);
        else {
            if(UF.same(u, v)) cout << 1 << endl;
            else cout << 0 << endl;
        }
    }
}
accuracy: 1
time_ms: 70
memory_kb: 3512
final_rank: 17

code_snippet: #include <cstdio>
#include <vector>
using namespace std;
class DisjointSet{
    public:
    vector<int> p,rank;
    DisjointSet(){}//构造函数，这样可以构建无参数类，下面也是，构造函数名字必须和类名一样
    DisjointSet(int size){
        p.resize(size,0);
        rank.resize(size,0);
        for(int i=0;i<size;i++){
            makeset(i);
        }
    }
    void makeset(int i){
        p[i]=i;
        rank[i]=0;//初始化所有元素指向自己
    }
    bool same(int a,int b){
        return findset(a)==findset(b);
    }
    void unite(int a,int b){
        link(findset(a),findset(b));
    }
    void link(int a,int b){
        if(rank[a]>rank[b]){
            p[b]=a;
        }else{
            p[a]=b;
            if(rank[a]==rank[b]){
                rank[b]++;
            }
        }
    }
    int findset(int a){
        if(a!=p[a]){
            p[a]=findset(p[a]);//实现路径压缩
        }
        return p[a];
    }
};
int main(){
    int n,q;
    scanf("%d %d",&n,&q);
    DisjointSet ds=DisjointSet(n);
    for(int i=0;i<q;i++){
        int c,x,y;
        scanf("%d %d %d",&c,&x,&y);
        if(c==0){
            ds.unite(x,y);
        }else if(c==1){
            if(ds.same(x,y)){
                printf("1\n");
            }else printf("0\n");
        }
    }
    return 0;
}
accuracy: 1
time_ms: 10
memory_kb: 2992
final_rank: 1

code_snippet: #include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define rep(i, s, e) for (int i = (int)(s); i < (int)(e); ++i)

struct UnionFind {
	vector<int> par;
	int group;
	UnionFind(int N) : par(N, -1), group(N) {}
	
	int root(int x) {
		if (par[x] < 0) return x;
		else return par[x] = root(par[x]);
	}
	
	bool merge(int x, int y) {
		if ((x = root(x)) == (y = root(y))) return false;
		if (par[x] > par[y]) swap(x, y);
		par[x] += par[y];
		par[y] = x;
		--group;
		return true;
	}
	
	bool same(int x, int y) {
		return root(x) == root(y);
	}
	
	int size(int x) {
		return -par[root(x)];
	}
};

int main() {
	cin.tie(nullptr);
	ios_base::sync_with_stdio(false);
	
	int N, Q;
	cin >> N >> Q;
	
	UnionFind uf(N);
	rep(query, 0, Q) {
		int t, x, y;
		cin >> t >> x >> y;
		
		if (t == 0) {
			uf.merge(x, y);
		} else {
			cout << (uf.same(x, y) ? 1 : 0) << '\n';
		}
	}
}
accuracy: 1
time_ms: 10
memory_kb: 3480
final_rank: 2

code_snippet: #include <iostream>
#include <vector>

class disjointSets {
public:
    std::vector<int> p, rank;

    // default constructor
    disjointSets() {}

    // constructor with size
    disjointSets(int size) {
        p.resize(size, 0);
        rank.resize(size, 0);
        for (int i = 0; i < size; i++) makeSet(i);
    }

    bool isSame(int x, int y) {
        return findSet(x) == findSet(y);
    }

    void uniteSets(int x, int y) {
        link(findSet(x), findSet(y));
    }

private:
    void makeSet(int x) {
        p[x] = x;
        rank[x] = 0;
    }

    void link(int x, int y) {
        if (rank[x] > rank[y]) {
            p[y] = x;
        } else {
            p[x] = y;
            if (rank[x] == rank[y]) rank[y]++;
        }
    }

    int findSet(int x) {
        if (x != p[x]) {
            p[x] = findSet(p[x]); // path compression
        }
        return p[x];
    }
};

int main() {
    int n, q;
    std::cin >> n >> q;

    disjointSets ds(n);

    int com, x, y;
    for (int i = 0; i < q; i++) {
        std::cin >> com >> x >> y;
        if (com == 0) {
            ds.uniteSets(x, y); // unite
        } else if (com == 1) { // same
            if (ds.isSame(x, y))
                std::cout << 1 << std::endl;
            else
                std::cout << 0 << std::endl;
        }
    }

    return 0;
}
accuracy: 1
time_ms: 60
memory_kb: 3504
final_rank: 9