UVa 11987 并查集 Almost Union-Find

原文戳这

与以往的并查集不同,这次需要一个删除操作。如果是叶子节点还好,直接修改父亲指针就好。

但是如果要是移动根节点,指向它的所有子节点也会跟着变化。

所以要增加一个永远不会被修改的虚拟根节点,这样就可以把一个点从集合中删除而不影响其它的点了。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6
 7 typedef long long LL;
 8
 9 const int maxn = 200000 + 10;
10
11 int n, m;
12
13 LL sum[maxn];
14 int cnt[maxn];
15 int pa[maxn];
16 int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); }
17
18 int main()
19 {
20     while(scanf("%d%d", &n, &m) == 2 && n)
21     {
22         for(int i = 1; i <= n; i++) { pa[i] = i + n; sum[i + n] = i; cnt[i + n] = 1; }
23         for(int i = 1; i <= n; i++) pa[i + n] = i + n;
24
25         int op, x, y;
26         while(m--)
27         {
28             scanf("%d", &op);
29             if(op == 1)
30             {
31                 scanf("%d%d", &x, &y);
32                 int px = findset(x), py = findset(y);
33                 if(px != py)
34                 {
35                     pa[px] = py;
36                     sum[py] += sum[px];
37                     cnt[py] += cnt[px];
38                 }
39             }
40             else if(op == 2)
41             {
42                 scanf("%d%d", &x, &y);
43                 int px = findset(x), py = findset(y);
44                 if(px != py)
45                 {
46                     pa[x] = py;
47                     sum[py] += x;
48                     sum[px] -= x;
49                     cnt[py]++; cnt[px]--;
50                 }
51             }
52             else
53             {
54                 scanf("%d", &x);
55                 int px = findset(x);
56                 printf("%d %lld\n", cnt[px], sum[px]);
57             }
58         }
59     }
60
61     return 0;
62 }

代码君

时间: 2024-10-14 07:19:12

UVa 11987 并查集 Almost Union-Find的相关文章

UVA 11987 并查集删点

并查集删点就是弄个id记录当前点的id,删除的时候将id设为新的id,忽略原来的id,当然还要注意去改变原来集合需要维护的性质比如元素个数等等. #include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #define REP(i,a,b) for(int i=a;i<=b;i++) #define MS0(a) m

并查集(union/find)

在计算机科学中,并查集是一种树型的数据结构,其保持着用于处理一些不相交集合(Disjoint Sets)的合并及查询问题.有一个联合-查找算法(union-find algorithm)定义了两个操作用于此数据结构: Find:确定元素属于哪一个子集.它可以被用来确定两个元素是否属于同一子集. Union:将两个子集合并成同一个集合. 因为它支持这两种操作,一个不相交集也常被称为联合-查找数据结构(union-find data structure)或合并-查找集合(merge-find set

UVa 10129 (并查集 + 欧拉路径) Play on Words

题意: 有n个由小写字母的单词,要求判断是否存在某种排列是的相邻的两个单词,前一个单词末字母与后一个单词首字母相同. 分析: 将单词的两个字母看做节点,则一个单词可以看做一条有向边.那么题中所求的排列就等价于该有向图中是否存在欧拉路径. 在判断之前,首先要确定这个图是连通的,代码中用并查集来实现. 回顾一下存在欧拉路径的条件,全都是偶点或者有且仅有两个奇点.我们用deg来记录每个点的度,出度为1,入度为-1. 程序中判断存在欧拉路径的条件就是:deg全为0 或者 有两个不为0的,其中一个为1一个

Union-Find(并查集): Quick union improvements

Quick union improvements1: weighting 为了防止生成高的树,将smaller tree放在larger tree的下面(smaller 和larger是指number of objects),而不是将larger tree放在smaller tree的下面(如上图中的第一种情况) Examples: quick-union & weighted quick-union 从上面的这个例子可以看到用quick-union时的树的高度很大,而用weighted qui

Union-Find(并查集): Quick union算法

Quick union算法 Quick union: Java implementation Quick union 性能分析 在最坏的情况下,quick-union的find root操作cost(访问array的次数)会达到N. 所以quick-union的性能也不好.

数据结构--并查集的原理及实现

一,并查集的介绍 并查集(Union/Find)从名字可以看出,主要涉及两种基本操作:合并和查找.这说明,初始时并查集中的元素是不相交的,经过一系列的基本操作(Union),最终合并成一个大的集合. 而在某次合并之后,有一种合理的需求:某两个元素是否已经处在同一个集合中了?因此就需要Find操作. 并查集是一种 不相交集合 的数据结构,设有一个动态集合S={s1,s2,s3,.....sn},每个集合通过一个代表来标识,该代表中集合中的某个元素. 比如,若某个元素 x 是否在集合 s1 中(Fi

UVA - 11987 - Almost Union-Find (又是并查集~)

UVA - 11987 Almost Union-Find Time Limit: 1000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Problem A Almost Union-Find I hope you know the beautiful Union-Find structure. In this problem, you're to implement som

uva 11987 Almost Union-Find (并查集)

题目大意: 三个操作. 1. 合并两个集合 2.把第一个元素放到第二个集合里 3.输出集合的数量和和.. 思路分析: 要用p记录这个元素所在集合编号,然后用编号建立并查集. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> using namespace std; typedef long long LL; int set[111111]; int cn

UVA 11987 - Almost Union-Find(并查集)

UVA 11987 - Almost Union-Find 题目链接 题意:给定一些集合,操作1是合并集合,操作2是把集合中一个元素移动到另一个集合,操作3输出集合的个数和总和 思路:并查集,关键在于操作2,对于并查集,要去除掉一个结点,如果该结点不是根那就好办了,那么就多开n个结点,每个结点初始父亲都是它的i + n,这样在移动的时候,就不用担心他是根结点了剩下就是普通的带权并查集了 代码: #include <cstdio> #include <cstring> const i