洛谷 [P3377] 左偏树(可并堆)

可并堆,就是可以合并的堆

注意并查集不能路径压缩,不然删除根节点时会出错

#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <cstdio>
using namespace std;
const int MAXN = 105005;
int init() {
	int rv = 0, fh = 1;
	char c = getchar();
	while(c < '0' || c > '9') {
		if(c == '-') fh = -1;
		c = getchar();
	}
	while(c >= '0' && c <= '9') {
		rv = (rv<<1) + (rv<<3) + c - '0';
		c = getchar();
	}
	return fh * rv;
}
int n, m;
struct LT{
	struct node {
		int l, r, val, dist, fa;
	}a[MAXN];
	int find(int x) {
		if(x != a[x].fa) return find(a[x].fa);
		return a[x].fa;
	}
	int merge(int u, int v) {
		if(!u) return v;
		if(!v) return u;
		if(a[u].val > a[v].val || (a[u].val == a[v].val && u > v)) swap(u, v);
		int &ul = a[u].l, &ur = a[u].r;
		ur = merge(ur, v);
		a[ur].fa = u;
		if(a[ul].dist < a[ur].dist) swap(ur, ul);
		a[u].dist = a[ur].dist + 1;
		return u;
	}
	void input() {
		a[0].dist = -1;
		for(int i = 1; i <= n; i++) a[i].fa = i;
		for(int i = 1; i <= n; i++) a[i].val = init();
	}
	void erase(int u) {
		int ul = a[u].l, ur = a[u].r;
		a[u].val = -1;
		a[ul].fa = ul; a[ur].fa = ur;
		merge(ul, ur);
	}
	void work() {
		input();
		for(int i = 1; i <= m; i++) {
			int opt = init();
			if(opt == 1){
				int x = init(), y = init();
				if(a[x].val == -1 || a[y].val == -1) continue;
				int r1 = find(x), r2 = find(y);
				if(r1 == r2) continue;
				merge(r1, r2);
			}else {
				int x = init();
				if(a[x].val == -1) {
					printf("-1\n");continue;
				}
				int r1 = find(x);
				printf("%d\n", a[r1].val);
				erase(r1);
			}
		}
	}
}lt;
int main() {
	//freopen("in.txt", "r", stdin);
	n = init(); m = init();
	lt.work();
	//fclose(stdin);
	return 0;
}
posted @ 2018-04-27 20:03  Mr_Wolfram  阅读(164)  评论(2编辑  收藏  举报