题意
起初给你一个空序列a, 有\(q\)次操作 (\(q\) <= \(5e5\))
每次操作有两种方案
. 在序列尾添加一个\(x\)
. 将现有序列值为\(x\)的,全部修改成\(y\) (\(x\) <= \(5e5\), \(y\) <= \(5e5\))
暴力必然不可取,很显然这题是一个并查集,但并不是简简单单的 在操作2中将 fa[x] = y.
比如,现在序列为 [1,2,3] 执行操作2,将1修改为2,序列现在为[2,2,3] ,fa[1] = 2, 但如果再添加向 2 序列尾添加1的话,发现序列用 fa[find(a[i])] 来表示的话是不对的,结果为 [2,2,3,2].
此次操作 2 应是独立的,不应该影响我后面序列。
故我们可以开一个last[x] 数组: (用于保存最近对x操作的时间点,默认初始化等于自己),开一个时间点拓展域p1 = 5e5,,操作 2 时,将 fa[last[x]] = fa[last[y]], 同时将p1给此时操作的x,同时用存时间的数组Fa[p1] 记录该时间点的 x , Fa[p1] = x, 然后p1 ++ ,以不影响后面的序列;
最后将操作的序列都放在 Fa[find(a[i])] 里面
需要注意的是,当 操作2下,if(x == y) 我们应该 continue,因为这是个无效修改。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <map>
#include <queue>
#include <vector>
#define endl '\n'
using namespace std;
void IOS() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
}
const int N = 1e6+5;
int a[N];
int fa[N];
int Fa[N];
int last[N];
int find(int x) {
if(fa[x] == x) return x;
else {
return fa[x] = find(fa[x]);
}
}
int main() {
int T;
IOS();
cin >> T;
int cnt = 0;
for (int i = 1; i < N; i ++) fa[i] = i,Fa[i] = i,last[i] = i;
int p1 = 5e5+1;
while(T -- ) {
int op;
cin >> op;
if(op == 1) {
int x;
cin >> x;
a[++cnt] = last[x];
}
else {
int x,y;
cin >> x >> y;
if(x!=y){
fa[last[x]] = last[y];
last[x] = p1;
Fa[p1] = x;
p1 ++;
}
}
}
for (int i = 1; i <= cnt; i ++ ) {
cout << Fa[find(a[i])] << ' ';
}
}