「UVA 11987」Almost Union-Find 「带权并查集」「思维」
Posted lim-817
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「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 << '
'
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
", cnt[pr], sum[pr]);
}
}
}
int main() {
#ifdef LOCAL
freopen("sample.in", "r", stdin);
#endif
while (~scanf("%d%d", &n, &m)) solve();
return 0;
}
以上是关于「UVA 11987」Almost Union-Find 「带权并查集」「思维」的主要内容,如果未能解决你的问题,请参考以下文章
UVa 11987 Almost Union-Find(支持删除操作的并查集)