题目链接
主席树叶子节点维护fa数组,每次的修改操作只会改变一个叶子结点的fa值,所以考虑动态开点。合并的时候启发式合并就行了。

#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
#define ft first
#define sd second
#define all(c) ((c).begin()), ((c).end())
#define mp(a, b) make_pair(a, b)
#define pb(x) push_back(x)
template<typename T>T gcd(T a, T b) {return b==0?a:gcd(b, a%b);}
#ifndef ONLINE_JUDGE
#define debug(fmt, ...) {printf("debug ");printf(fmt,##__VA_ARGS__);puts("");}
#else
#define debug(fmt, ...)
#endif
const int maxn = 4e5+5;
typedef long long ll;
const ll mod = 1e9+7;
int Case = 1;
int n, m, tot;
int ch[maxn<<5][2], fa[maxn<<5], root[maxn<<5], dep[maxn<<5];
int newnode() {
    tot++;
    ch[tot][0] = ch[tot][1] = 0;
    return tot;
}
void build(int &rt, int l, int r) {
    rt = newnode();
    if(l == r) {fa[rt] = l;dep[rt] = 1;return;}
    int mid = (l+r)/2;
    build(ch[rt][0], l, mid);
    build(ch[rt][1], mid+1, r);
}
void insert(int &rt, int tc, int l, int r, int ida, int idb) {
    rt = newnode();
    ch[rt][1] = ch[tc][1];ch[rt][0] = ch[tc][0];
    if(l == r) {
        fa[rt] = fa[idb];
        dep[rt] = dep[idb];
        if(dep[ida] == dep[idb]) dep[rt]++;
        return;
    }
    int mid = (l+r)/2;
    if(fa[ida] <= mid) insert(ch[rt][0], ch[tc][0], l, mid, ida, idb);
    else insert(ch[rt][1], ch[tc][1], mid+1, r, ida, idb);
}
int query(int rt, int l, int r, int pos) {
    if(l == r) return rt;
    int mid = (l+r)/2;
    if(pos <= mid) return query(ch[rt][0], l, mid, pos);
    else return query(ch[rt][1], mid+1, r, pos);
}
int find(int i, int x) {
    int rt = query(root[i], 1, n, x);
    while(fa[rt] != x) {
        x = fa[rt];
        rt = query(root[i], 1, n, fa[rt]);
    }
    return rt;
}
void _union(int i, int x, int y) {
    int fx = find(i, x), fy = find(i, y);
    if(fa[fx] == fa[fy]) return;
    if(dep[fx] > dep[fy]) insert(root[i], root[i-1], 1, n, fx, fy);
    else insert(root[i], root[i-1], 1, n, fy, fx);
}
void solve() {
    cin>>n>>m;int last = 0;
    build(root[0], 1, n);
    for(int i = 1; i <= m; i++) {
        int op, a, b, k;cin>>op;
        if(op == 1) {
            root[i] = root[i-1];
            cin>>a>>b;
            a ^= last;b ^= last;
            _union(i, a, b);
        }
        else if(op == 2) {
            cin>>k;k ^= last;root[i] = root[k];
        }
        else {
            root[i] = root[i-1];
            cin>>a>>b;
            a ^= last;b ^= last;
            cout<<(last = (fa[find(i, a)] == fa[find(i, b)]))<<endl;
        }
    }
    return;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif
    while(Case--) {
        solve();
    }
    return 0;
}