思路
對於操作 1,我們可以看做將 \(x\) 號集合與 \(y\) 號集合合併,並將原本的 \(y\) 號集合重新開一個並查集維護。
對於操作 2,我們可以開一個陣列維護每一個球所在哪一個並查集中。
對於操作 3,在操作 1 中維護每一個並查集對於了哪一個箱子即可。
因為 \(n + q \leq 6 \times 10^5\),所以陣列開 \(6 \times 10^5\) 即可。
Code
#include <bits/stdc++.h>
#define re register
using namespace std;
const int N = 6e5 + 10;
int n,q,idx,num;
int f[N],bd[N],nd[N],box[N];
/*
f 維護並查集
bd 維護每一個箱子對應的並查集
nd 維護每一個球對應的並查集
box 維護每一個並查集對於的箱子
*/
inline int read(){
int r = 0,w = 1;
char c = getchar();
while (c < '0' || c > '9'){
if (c == '-') w = -1;
c = getchar();
}
while (c >= '0' && c <= '9'){
r = (r << 1) + (r << 3) + (c ^ 48);
c = getchar();
}
return r * w;
}
inline int find(int x){
if (f[x] != x) return f[x] = find(f[x]);
return f[x];
}
int main(){
n = idx = num = read();
q = read();
for (re int i = 1;i <= n;i++) f[i] = bd[i] = nd[i] = box[i] = i;
while (q--){
int op;
op = read();
if (op == 1){
int x,y;
x = read();
y = read();
f[bd[y]] = find(bd[x]);
bd[y] = ++idx;
f[idx] = idx;
box[idx] = y;
}
else if (op == 2){
int x;
x = read();
nd[++num] = bd[x];
}
else{
int x;
x = read();
printf("%d\n",box[find(nd[x])]);
}
}
return 0;
}