原题链接
左偏树(满足堆性质 + 左偏性质).
模板.
注意:及时更新并查集.
代码如下:
#include <cstdio>
#include <cstring>
#include <cctype>
#include <iostream>
#include <cmath>
using namespace std;
inline int read() {
int x = 0, f = 0; char ch = getchar();
while (!isdigit(ch)) f = ch == '-', ch = getchar();
while (isdigit(ch)) x = (x << 3) + (x << 1) + (ch ^ 48), ch = getchar();
return f ? -x : x;
}
inline void print(int x) {
if (x < 0) putchar('-'), x = -x;
if (x < 10) putchar(x + '0');
else {
print(x / 10);
putchar(x % 10 + '0');
}
}
const int N = 1e6 + 10;
int n, m;
int val[N], ls[N], rs[N], rt[N], d[N];
int find(int x) { return rt[x] == x ? x : rt[x] = find(rt[x]); }
int merge(int x, int y) {
if ((!x) || (!y)) return x + y;
if (val[x] < val[y]) swap(x, y);
rs[x] = merge(rs[x], y);
if (d[ls[x]] < d[rs[x]]) swap(ls[x], rs[x]);
d[x] = d[rs[x]] + 1;
return x;
}
int fih(int x) {
// printf("fih(%d)\n", x);
if ((!ls[x]) && (!rs[x])) { val[x] >>= 1; return x; } // 考虑左右儿子均空.
int la = merge(ls[x], rs[x]);
// printf("la = merge(%d, %d) = %d\n", la, ls[x], rs[x]);
rt[x] = rt[rs[x]] = rt[ls[x]] = la;
ls[x] = rs[x] = d[x] = 0; val[x] >>= 1;
return rt[x] = rt[la] = merge(x, la);
}
int main() {
while (~scanf("%d", &n)) {
memset(val, 0, sizeof(val));
memset(ls, 0, sizeof(ls));
memset(rs, 0, sizeof(rs));
memset(rt, 0, sizeof(rt));
memset(d, 0, sizeof(d));
for (int i = 1; i <= n; ++i) rt[i] = i;
for (int i = 1; i <= n; ++i) {
val[i] = read();
}
m = read();
while (m--) {
int x = read(), y = read();
x = find(x); y = find(y);
if (x == y) print(-1), putchar('\n');
else {
int lax = fih(x), lay = fih(y);
rt[lax] = rt[lay] = merge(lax, lay);
print(val[find(lax)]); putchar('\n');
}
}
}
return 0;
}