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

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])] << ' ';	 	
	}
}

上一篇:CodeForces - 607B Zuma


下一篇:Codeforces Round #761 (Div. 2)