「UVA 11987」Almost Union-Find 「带权并查集」「思维」

你发现,这个第二个操作不可能用普通并查集来搞,很棘手

但是你考虑一下,并查集维护的是个森林结构,并且路径压缩的时候每个森林的根是不会变的,

也就是意味着每删掉一个点你需要让他的踪影消失匿迹即可,并不需要让他在原有的树结构上消失。

具体怎么消失?把贡献全在根上减掉即可,再新建一个新点连进去。

这个新点可以用id数组表示,即id[x]为x节点现在的编号。

#include <bits/stdc++.h>

#define test(...) fprintf(stderr, __VA_ARGS__)
#define dbg(x) cerr << #x << " = " << x << '\n'

using namespace std;

typedef long long ll;
typedef pair <int, int> pii;
typedef vector <int> vi;
typedef unsigned int ui;
typedef vector <pair <int, int> > edges;

const int N = 100010;
int n, m, id[N], par[N], tot, cnt[N];
ll sum[N];
int find_par(int x) {
    return x == par[x] ? par[x] : par[x] = find_par(par[x]);
}
void solve() {
    for (int i = 1; i <= n; ++i)
        id[i] = i, par[i] = i, sum[i] = i, cnt[i] = 1;
    tot = n;
    while (m--) {
        int op, p, q;
        scanf ("%d%d", &op, &p);
        if (op == 1) {
            scanf ("%d", &q);
            int rp = id[p], rq = id[q];
            rp = find_par(rp);
            rq = find_par(rq);
            if (rp == rq) continue;
            par[rp] = rq;
            sum[rq] += sum[rp];
            cnt[rq] += cnt[rp];
        } else if (op == 2) {
            scanf ("%d", &q);
            int rp = id[p], rq = id[q];
            rp = find_par(rp);
            rq = find_par(rq);
            if (rp == rq) continue;
            cnt[rp]--;
            sum[rp] -= p;
            sum[rq] += p;
            cnt[rq]++;
            id[p] = ++tot;
            par[id[p]] = rq;
        } else if (op == 3) {
            int pr = find_par(id[p]);
            printf("%d %lld\n", cnt[pr], sum[pr]);
        }
    }
}

int main() {
#ifdef LOCAL
    freopen("sample.in", "r", stdin);
#endif
    while (~scanf("%d%d", &n, &m)) solve();
  return 0;
}

原文地址:https://www.cnblogs.com/LiM-817/p/12337442.html

时间: 2024-08-10 21:42:48

「UVA 11987」Almost Union-Find 「带权并查集」「思维」的相关文章

「带权并查集」奇偶游戏

奇偶游戏 原题链接:奇偶游戏 题目大意 给你N个区间,每个区间给你它含1的奇偶性,问你哪些询问逻辑上冲突 题目题解 一道带权并查集的题,让我对带权并查集有了更深入的理解,带权并查集可以分为两种(在这道题中) "边带权"并查集 "扩展域"并查集 两种方法都是思维上的不同所造成的,其中第一种解法是最常见的,第二种解法在代码实现上是最简单的,我们先来对第一种进行探究 边带权,很明显,我们要在并查集的边上进行一个储存边权的操作,我们这里用d来表示当前节点到根节点的Xor值,

UVA 12232 - Exclusive-OR(带权并查集)

UVA 12232 - Exclusive-OR 题目链接 题意:有n个数字.一開始值都不知道,每次给定一个操作,I a v表示确认a值为v,I a b v,表示确认a^b = v,Q k a1 a2 a3 ... ak.表示推断这些数字的异或值是否能确定.能确定就输出值,假设有矛盾就停止 思路:带权并查集,权表示和父结点的异或值,那么多数推断的时候,仅仅要全部数字和他的父结点的异或值的异或值.假设父结点的个数是偶数个.那么依据异或的性质能抵消掉,是能够判定的.假设不为偶数,就是不能判定. 注意

UVa 11987 Almost Union-Find(支持删除操作的并查集)

传送门 Description 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

UVA 3027 Corporative Network 带权并查集、

题意:一个企业要去收购一些公司把,使的每个企业之间互联,刚开始每个公司互相独立 给出n个公司,两种操作 E I:询问I到I它连接点最后一个公司的距离 I I J:将I公司指向J公司,也就是J公司是I公司的上级,距离为abs(I-J)%1000(貌似G++不支持abs,PE了两发) 思路:转化一下题意就行了,首先刚开始的时候每个公司都是独立的,I操作就是并查集中合并操作,将I这课树并到J这个树上, E操作要求的东西就是 I到I的根节点的距离,先看一个没有路径压缩直接暴力的方法把.(本以为不会过的,

UVA - 10004 Bicoloring(判断二分图——交叉染色法 / 带权并查集)

d.给定一个图,判断是不是二分图. s.可以交叉染色,就是二分图:否则,不是. 另外,此题中的图是强连通图,即任意两点可达,从而dfs方法从一个点出发就能遍历整个图了. 如果不能保证从一个点出发可以遍历整个图,那么编程要注意了,应该从每个点出发遍历一次. s2.带权并查集来判断,略复杂.先略过.先上个博客:http://blog.csdn.net/zsc09_leaf/article/details/6727622 c.邻接矩阵,bfs #include<iostream> #include&

UVA 10301 (最大粘合的换有多少个,并查集)

Rings and Glue Time Limit: 1 second Memory Limit: 32 MB Little John is in big trouble. Playing with his different-sized (and colored!) rings and glue seemed such a good idea. However, the rings now lay on the floor, glued together with some-thing tha

UVa 10129 Play On Words【欧拉道路 并查集 】

题意:给出n个单词,问这n个单词能否首尾接龙,即能否构成欧拉道路 按照紫书上的思路:用并查集来做,取每一个单词的第一个字母,和最后一个字母进行并查集的操作 但这道题目是欧拉道路(下面摘自http://blog.csdn.net/hcbbt/article/details/9316301) 关于欧拉道路(from Titanium大神): 判断有向图是否有欧拉路 1.判断有向图的基图(即有向图转化为无向图)连通性,用简单的DFS即可.如果图都不连通,一定不存在欧拉路 2.在条件1的基础上   对于

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

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

「并查集」程序自动分析

程序自动分析 原题链接:程序自动分析 题目大意 给你很多逻辑关系,判断是否有冲突 题目题解 先将两个逻辑分开来看,前一个逻辑存在那么后一个逻辑一定不存在,如果存在那么答案就错误了,可以用并查集维护,详细见代码 //#define fre yes #include <cstdio> #include <iostream> #include <algorithm> const int N = 1000005; struct message { int x, y, e; }