Time Limit: 1000MS | Memory Limit: Unknown | 64bit IO Format: %lld & %llu |
Description
Problem A
Almost Union-Find
I hope you know the beautiful Union-Find structure. In this problem, you‘re to implement something similar, but not identical.
The data structure you need to write is also a collection of disjoint sets, supporting 3 operations:
1 p q
Union the sets containing p and q. If p and q are already in the same set, ignore this command.
2 p q
Move p to the set containing q. If p and q are already in the same set, ignore this command
3 p
Return the number of elements and the sum of elements in the set containing p.
Initially, the collection contains n sets: {1}, {2}, {3}, ..., {n}.
Input
There are several test cases. Each test case begins with a line containing two integers n and m (1<=n,m<=100,000), the number of integers, and the number of commands. Each of the next m lines contains a command. For every operation, 1<=p,q<=n. The input is
terminated by end-of-file (EOF). The size of input file does not exceed 5MB.
Output
For each type-3 command, output 2 integers: the number of elements and the sum of elements.
Sample Input
5 7 1 1 2 2 3 4 1 3 5 3 4 2 4 1 3 4 3 3
Output for the Sample Input
3 12 3 7 2 8
Explanation
Initially: {1}, {2}, {3}, {4}, {5}
Collection after operation 1 1 2: {1,2}, {3}, {4}, {5}
Collection after operation 2 3 4: {1,2}, {3,4}, {5} (we omit the empty set that is produced when taking out 3 from {3})
Collection after operation 1 3 5: {1,2}, {3,4,5}
Collection after operation 2 4 1: {1,2,4}, {3,5}
Rujia Liu‘s Present 3: A Data Structure Contest Celebrating the 100th Anniversary of Tsinghua University
Special Thanks: Yiming Li
Note: Please make sure to test your program with the gift I/O files before submitting!
带删除的并查集.
操作2实际上是将p从原来的集合中删除,再加入到q所在的集合中。
并查集没有删除的操作,于是换个思路,让p点在其原来的集合中的影响为0,在开辟一个新的节点作为编号为p的节点,加入q所在集合。
用id[i]=ii代表数字i当前的位置,每次删除把id[i]指向其他位置,原来的位置舍去。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int MAXN = 200000+100; int parent[MAXN]; int cnt[MAXN]; int sum[MAXN]; int n, m; int dex; int id[MAXN]; void make_set() { dex = n; for (int i = 0; i <= n; i++) { parent[i] = i; cnt[i] = 1; sum[i] = i; id[i] = i; } } int find_set(int t) { if (parent[t] == t) return t; else return parent[t] = find_set(parent[t]); } void union_set(int a, int b) { int t1 = find_set(a); int t2 = find_set(b); if (t1 != t2) { parent[t2]=t1; cnt[t1] += cnt[t2]; sum[t1] += sum[t2]; } } void move(int a) { int p = find_set(id[a]); cnt[p]--; sum[p] -= a; //消除该位置的点在原来集合中的影响 id[a] = ++dex; //开辟新的位置表示这个编号的点 parent[dex] = dex; cnt[dex] = 1; sum[dex] = a; } int main() { while (scanf("%d%d", &n, &m) != EOF) { make_set(); int op; int a, b; while (m--) { scanf("%d", &op); if (op == 1) { scanf("%d%d", &a, &b); union_set(id[a], id[b]); } else if (op == 2) { scanf("%d%d", &a, &b); int t1 = find_set(id[a]); int t2 = find_set(id[b]); if (t1 != t2) { move(a); //从原来集合中移除 union_set(id[a], id[b]); //合并到新的集合中 } } else { scanf("%d", &a); int p = find_set(id[a]); printf("%d %d\n", cnt[p], sum[p]); } } } }
版权声明:本文为博主原创文章,未经博主允许不得转载。