题意:
操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作)
操作2: 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作)
做法:
左偏树模板。
代码:
/*************************************************************
Problem: luogu 3377 【模板】左偏树(可并堆)
User: bestFy
Language: C++
Result: Accepted
Time: 72 ms
Memory: 3.98 MB
Submit_Time: 2018-01-11 13:21:17
*************************************************************/
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cctype>
using namespace std;
typedef long long LL;
inline LL read()
{
char ch = getchar(); LL x = 0; int op = 1;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') op = -1;
for(; isdigit(ch); ch = getchar()) x = x*10 + ch-'0';
return x*op;
}
inline void write(LL a) { if(a < 0) putchar('-'); if(a >= 10) write(a/10); putchar(a%10+'0'); }
const int N = 100010;
int n, m;
int a[N], dep[N], ls[N], rs[N], fa[N];
inline int getFa(int x) { return fa[x] == x ? x : getFa(fa[x]); }
inline int merge(int x, int y)
{
if(!x) return y;
if(!y) return x;
if(a[x] > a[y] || a[x] == a[y] && x > y) swap(x, y);
rs[x] = merge(rs[x], y);
fa[rs[x]] = x;
if(dep[ls[x]] < dep[rs[x]]) swap(ls[x], rs[x]);
dep[x] = dep[rs[x]]+1;
return x;
}
int main()
{
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
for(int i = 1; i <= n; i ++) fa[i] = i;
while(m --) {
int opt = read(), x = read(), y;
if(opt == 1) {
y = read();
if(a[x] == -1 || a[y] == -1) continue;
x = getFa(x); y = getFa(y);
if(x != y) merge(x, y);
} else {
if(a[x] == -1) puts("-1");
else {
x = getFa(x); printf("%d\n", a[x]); a[x] = -1;
fa[ls[x]] = ls[x]; fa[rs[x]] = rs[x]; merge(ls[x], rs[x]);
}
}
}
return 0;
}