UVA 11987 Almost Union-Find (并查集+技巧)

题目链接:https://www.luogu.com.cn/problem/UVA11987

唯一需要考虑的就是操作二,将某元素从一个并查集移动到另一个并查集中

建立一个新节点代表该元素,将原来的元素留在原位,原来的并查集减掉,新的并查集加上即可

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

const int maxn = 100010;

int n, m, tot;
int fa[maxn], cnt[maxn], sum[maxn], id[maxn]; 

int find(int x){
	return (fa[x] == x) ? x : find(fa[x]);
}

ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }

int main(){
	while(scanf("%d%d", &n, &m) != EOF){
		tot = n;
		for(int i = 1 ; i <= n ; ++i) fa[i] = i, cnt[i] = 1, sum[i] = i, id[i] = i;
		
		int op, p, q;
		for(int i = 1 ; i <= m ; ++i){
			scanf("%d", &op);
			if(op == 1){
				scanf("%d%d", &p, &q);
				int u = find(id[p]), v = find(id[q]);
				if(u != v){
					fa[u] = v;
					cnt[v] += cnt[u];
					sum[v] += sum[u];					
				}
			} else if(op == 2){
				scanf("%d%d", &p, &q);
				int u = find(id[p]), v = find(id[q]); 
				if(u != v){
					id[p] = ++tot;
					cnt[u]--;
					sum[u] -= p;
					fa[id[p]] = v;
					++cnt[v];
					sum[v] += p;
				}
			} else{
				scanf("%d", &p);
				int u = find(id[p]);
				printf("%d %d\n", cnt[u], sum[u]);
			}
		}
	} 
	return 0;
}
posted @ 2021-09-04 21:46  Tartarus_li  阅读(37)  评论(0编辑  收藏  举报