题目地址:P1456 Monkey King
一道挺模板的左偏树题
左偏树
优先队列在信息学竞赛中十分常见,在统计问题、最值问题、模拟问题和贪心问题等等类型的题目中,优先队列都有着广泛的应用。二叉堆是一种常用的优先队列,它编程简单,效率高,但如果问题需要对两个优先队列进行合并,二叉堆的效率就无法令人满意了。本文介绍的左偏树,可以很好地解决这类问题。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 6;
int n, m, f[N], a[N], l[N], r[N], d[N];
int get(int x) {
if (x == f[x]) return x;
return f[x] = get(f[x]);
}
inline int merge(int x, int y) {
if (!x || !y) return x + y;
if (a[x] < a[y]) swap(x, y);
r[x] = merge(r[x], y);
f[r[x]] = x;
if (d[l[x]] < d[r[x]]) swap(l[x], r[x]);
d[x] = d[r[x]] + 1;
return x;
}
inline void pop(int x) {
f[l[x]] = l[x], f[r[x]] = r[x];
f[x] = merge(l[x], r[x]);
l[x] = r[x] = 0;
}
inline void work() {
d[0] = -1;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
f[i] = i;
d[i] = l[i] = r[i] = 0;
}
cin >> m;
while (m--) {
int x, y;
scanf("%d %d", &x, &y);
int fx = get(x), fy = get(y);
if (fx == fy) puts("-1");
else {
pop(fx), pop(fy);
a[fx] >>= 1, a[fy] >>= 1;
f[fx] = merge(fx, f[fx]);
f[fy] = merge(fy, f[fy]);
fx = get(fx), fy = get(fy);
printf("%d\n", a[merge(fx,fy)]);
}
}
}
int main() {
while (cin >> n) work();
return 0;
}