Luogu P3377【模板】左偏树(可并堆)

采用了jls的左偏树写法,非常好写...

额外用一个并查集维护集合关系即可,注意路径压缩。

#include <bits/stdc++.h>

using namespace std;
typedef long long LL;

#define LOG(...) fprintf (stderr, __VA_ARGS__)
#define pb push_back
#define mp make_pair
#define SZ(x) ((int)(x).size())
#define ALL(x) (x).begin(), (x).end()

const int INF = 0x3f3f3f3f, N = 100005;
const LL INFL = 0x3f3f3f3f3f3f3f3fll;

int n, m, rt[N], cnt, f[N], a[N]; 
struct HeapNode {
	int w, ls, rs, sz;
	HeapNode (int w=0, int ls=0, int rs=0, int sz=0): w(w), ls(ls), rs(rs), sz(sz){}
}e[N];

int find (int x) {
	return x == f[x] ? f[x] : f[x] = find(f[x]);
}
int merge (int x, int y) {
	if (!x || !y) return x+y;
	if (e[x].w > e[y].w || (e[x].w == e[y].w && x > y)) swap(x, y);
	e[x].rs = merge(e[x].rs, y);
	if (e[e[x].rs].sz > e[e[x].ls].sz) swap(e[x].ls, e[x].rs);
	e[x].sz = e[e[x].rs].sz + 1;
	return x; 
}
int main() {
#ifdef LiM_817
	double cl = clock();
	freopen ("input.txt", "r", stdin);
#endif
	

	scanf ("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) {
		rt[i] = ++cnt; f[i] = i; 
		int w; scanf ("%d", &w);
		a[i] = w; 
		e[rt[i]] = (HeapNode) {w, 0, 0, 1}; 
	}
	
	while (m--) {
		int op, x, y;
		scanf ("%d%d", &op, &x);
		if (op == 1) {
			scanf ("%d", &y);
			if (a[x] == -1 || a[y] == -1) continue;
			x = find(x), y = find(y);
			rt[x] = merge(rt[x], rt[y]);
			f[y] = x; 
		}
		else if (op == 2) {
			if (a[x] == -1) {
				puts("-1");
				continue;
			}
			int t = find(x);
			printf ("%d
", e[rt[t]].w);
			a[rt[t]] = -1; 
			rt[t] = merge(e[rt[t]].ls, e[rt[t]].rs);
		}
	}
#ifdef LiM_817
	cerr << fixed << setprecision(2) << "Time ellapsed: " << ((double)(clock() - cl) / CLOCKS_PER_SEC) << "s
";
#endif
	return 0;
}
原文地址:https://www.cnblogs.com/LiM-817/p/11934607.html