来自2016集训队作业。
你需要维护一棵带插入和删除的treap,多次询问某两点间的treap上距离。
记treap节点的树键值为key,堆权值为pri,把treap躺下来就得到了一个按key的rank为下标,pri为权值的数组,则求两个点的lca显然就是区间内最大权值的那个点。
于是现在需要计算点到根的距离。等价于计算作为左儿子、右儿子往上跳了多少次,现在考虑作为右儿子往上跳的次数,每次能跳则说明跳到的那个点的pri一定是区间内最大的,左儿子网上跳同理。因此对于位置
u
我们只需要计算有多少个
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for (int i = a; i <= b; i ++)
const int N = 200007;
const int S = 524291;
typedef unsigned int u32;
typedef int seg[S];
typedef u32 s32[S];
seg sum_l, sum_r;
s32 mx;
map<u32, int> ms;
int ql, qr, p, n;
u32 w;
#define lc (u << 1)
#define rc (u << 1 | 1)
#define L lc, l, m
#define R rc, m + 1, r
int gao_l(int u, int l, int r, u32 v) {
if (mx[u] <= v) return 0;
if (l == r) {
return mx[u] > v;
}
int m = (l + r) >> 1;
int t = gao_l(R, v);
if (t) t += sum_l[u] - sum_l[rc];
else {
assert(v >= mx[rc]);
t = gao_l(L, v);
}
return t;
}
int gao_r(int u, int l, int r, u32 v) {
if (mx[u] <= v) return 0;
if (l == r) return mx[u] > v;
int m = (l + r) >> 1;
int t = gao_r(L, v);
if (t) t += sum_r[u] - sum_r[lc];
else {
assert(v >= mx[lc]);
t = gao_r(R, v);
}
return t;
}
void modi(int u, int l, int r) {
if (l == r) {
mx[u] = w;
sum_l[u] = sum_r[u] = 1;
return;
}
int m = (l + r) >> 1;
if (p <= m) modi(L); else modi(R);
mx[u] = max(mx[lc], mx[rc]);
sum_l[u] = sum_l[rc] + gao_l(L, mx[rc]);
sum_r[u] = sum_r[lc] + gao_r(R, mx[lc]);
}
u32 pre;
int get_l(int u, int l, int r) {
if (ql <= l && r <= qr) {
int t = 0;
if (!pre) t = sum_l[u];
else t = gao_l(u, l, r, pre);
pre = max(pre, mx[u]);
return t;
}
int m = (l + r) >> 1, t = 0;
if (qr > m) t += get_l(R);
if (ql <= m) t += get_l(L);
return t;
}
int get_r(int u, int l, int r) {
if (ql <= l && r <= qr) {
int t = 0;
if (!pre) t = sum_r[u];
else t = gao_r(u, l, r, pre);
pre = max(pre, mx[u]);
return t;
}
int m = (l + r) >> 1, t = 0;
if (ql <= m) t += get_r(L);
if (qr > m) t += get_r(R);
return t;
}
int get_dis(int u) {
assert(u);
int ret = 0;
ql = 1, qr = u, pre = 0;
ret += get_l(1, 1, n);
ql = u, qr = n, pre = 0;
ret += get_r(1, 1, n);
return ret;
}
u32 t;
void que(int u, int l, int r) {
if (ql <= l && r <= qr) {
t = max(t, mx[u]);
return;
}
int m = (l + r) >> 1;
if (ql <= m) que(L);
if (qr > m) que(R);
}
#include <ext/pb_ds/hash_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
__gnu_pbds::gp_hash_table<u32, int> cur;
u32 val[N];
void query(int u, int v) {
if (u > v) swap(u, v);
ql = u, qr = v, t = 0;
que(1, 1, n);
t = cur[t];
int d1 = get_dis(u);
int d2 = get_dis(v);
int d3 = get_dis(t);
printf("%d\n", d1 + d2 - 2 * d3);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(0);
int m;
static int cmd[N];
static u32 a[N], b[N];
cin >> m;
rep (i , 1 , m) {
cin >> cmd[i] >> a[i];
if (cmd[i] != 1) cin >> b[i];
if (cmd[i] == 0) ms[a[i]] = 0;
}
for (auto &v: ms) v.second = ++ n;
rep (i , 1 , m) {
switch (cmd[i]) {
case 0: p = ms[a[i]]; w = b[i]; cur[ b[i]] = p; val[p] = w; modi(1, 1, n); break;
case 1: p = ms[a[i]]; w = 0; cur[val[p]] = 0; val[p] = 0; modi(1, 1, n); break;
case 2: query(ms[a[i]], ms[b[i]]); break;
}
}
return 0;
}