P3377 【模板】左偏树/可并堆

Sol

启发式合并过了/hanx

考虑每次把小的暴力合并到大的上面,复杂度 \(O(n\log^2 n)\)

Code

#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
#define x first
#define y second
#define pb push_back
#define pf push_front
#define desktop "C:\\Users\\incra\\Desktop\\"
#define IOS ios :: sync_with_stdio (false),cin.tie (0),cout.tie (0)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair <int,int> PII;
const int dx[] = {1,0,-1,0},dy[] = {0,-1,0,1};
template <typename T1,typename T2> bool tomax (T1 &x,T2 y) {
	if (y > x) return x = y,true;
	return false;
}
template <typename T1,typename T2> bool tomin (T1 &x,T2 y) {
	if (y < x) return x = y,true;
	return false;
}
LL power (LL a,LL b,LL p) {
	LL ans = 1;
	while (b) {
		if (b & 1) ans = ans * a % p;
		a = a * a % p;
		b >>= 1;
	}
	return ans;
}
int fastio = (IOS,0);
#define endl '\n'
#define puts(s) cout << (s) << endl
const int N = 100010;
int n,m;
__gnu_pbds :: priority_queue <pair <LL,int> > heap[N];
int p[N];
bool del[N];
int find (int x) {
	return p[x] == x ? x : p[x] = find (p[x]);
}
void mian () {
	cin >> n >> m;
	for (int i = 1;i <= n;i++) p[i] = i;
	for (int i = 1;i <= n;i++) {
		LL x;
		cin >> x;
		heap[i].push ({-x,-i});
	}
	while (m--) {
		int op;
		cin >> op;
		if (op == 1) {
			int a,b;
			cin >> a >> b;
			if (find (a) == find (b) || del[a] || del[b]) continue;
			a = find (a),b = find (b);
			if (heap[a].size () < heap[b].size ()) swap (a,b);
			heap[a].join (heap[b]);
			p[b] = a;
		}
		else {
			int x;
			cin >> x;
			if (del[x]) {
				puts ("-1");
				continue;
			}
			x = find (x);
			del[-heap[x].top ().y] = 1;
			cout << -heap[x].top ().x << endl;
			heap[x].pop ();
		}
	}
}
int main () {
	int T = 1;
	// cin >> T;
	while (T--) mian ();
	return 0;
}
posted @ 2025-07-21 22:50  incra  阅读(8)  评论(0)    收藏  举报