洛谷 P3377 【模板】左偏树(可并堆)题解 左偏树模板题
题目链接:https://www.luogu.com.cn/problem/P3377
维护左偏树的同时还需要维护一个并查集。
但是并查集也就一个 find 操作。
pop 的时候更新 f[x]
的操作很神奇。
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, m, op, x, y, val[maxn], ls[maxn], rs[maxn], f[maxn], dis[maxn];
bool vis[maxn];
// 并查集部分
void init() {
for (int i = 1; i <= n; i++) f[i] = i;
}
int find(int x) {
return x == f[x] ? x : f[x] = find(f[x]);
}
// 左偏树部分
void push_up(int x) {
if (dis[rs[x]] > dis[ls[x]]) swap(rs[x], ls[x]);
dis[x] = dis[rs[x]] + 1;
}
int merge(int x, int y) {
if (!x || !y) return x + y;
if (val[x] > val[y] || val[x] == val[y] && x > y) swap(x, y);
f[rs[x] = merge(rs[x], y)] = x;
push_up(x);
return x;
}
void pop(int x) {
if (vis[x]) return;
vis[x] = true;
f[ls[x]] = ls[x];
f[rs[x]] = rs[x];
f[x] = merge(ls[x], rs[x]);
}
int main() {
scanf("%d%d", &n, &m);
init();
for (int i = 1; i <= n; i++)
scanf("%d", val+i);
while (m--) {
scanf("%d%d", &op, &x);
if (op == 1) {
scanf("%d", &y);
if (!vis[x] && !vis[y] && x != y) {
x = find(x), y = find(y);
merge(x, y);
}
}
else {
if (vis[x]) puts("-1");
else {
x = find(x);
printf("%d\n", val[x]);
pop(x);
}
}
}
return 0;
}