Educational Codeforces Round 119 (Rated for Div. 2) E. Replace the Numbers

题意

起初给你一个空序列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])] << ' ';
	}
}

posted @ 2021-12-19 10:44  Xiaomostream  阅读(87)  评论(0编辑  收藏  举报