题解:P9358 [ICPC 2022 Xi'an R] Bridge
感谢 @Lgx_Q 大佬教导的 FHQ 做法。
前面的部分和题解区其它平衡树做法大致相同,将第一次到达某一列时所在的坐标写成一个序列,在 \((x,y)\) 建桥就相当于交换这两部分:
- \((x,y)\) 所在序列中,\((x,y)\) 后面的部分;
- \((x+1,y)\) 所在序列中,\((x+1,y)\) 后面的部分。
如图是样例前两次建桥后,对序列的影响,颜色代表 \(x\)。
所以每一行都建立一个 FHQ Treap,以 \(1\sim m\) 为 key 值,维护其序列即可,找答案就是找到这一行的 Treap,不断向右跳找到最后的点是哪里。
发现很多点都是不需要的,所以只存起点,建桥的关键点,终点即可。注意按顺序插入 FHQ Treap 和去重。
如何找关键点现在在哪个 Treap 中?令每一行的起点在 FHQ 中的点编号都等于行编号,rnd 值赋为无穷大(大根堆),这样子每棵 Treap 的根的点编号都是他所维护的行的编号。
点击查看代码
#include <bits/stdc++.h>
#define int long long
#define pii pair<int, int>
#define fi first
#define se second
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
mt19937 rnd(time(0));
const int N = 4e6 + 10, oo = 1e18;
int n, m, q;
struct OPT {
int opt, x, y, id[2];
} a[N];
vector<pii> upd[N];
bool cmp(pii x, pii y) {
return a[x.fi].y < a[y.fi].y;
}
namespace FHQ {
struct TREE {
int ls, rs, fa, sz, key, rnd, col;
} t[N];
int idx, root[N];
void push_up(int rt) {
t[rt].sz = t[t[rt].ls].sz + t[t[rt].rs].sz + 1;
t[t[rt].ls].fa = t[t[rt].rs].fa = rt;
}
void split(int rt, int v, int &l, int &r) {
if (!rt) {
l = r = 0;
return;
}
if (t[rt].key <= v) {
l = rt;
split(t[rt].rs, v, t[rt].rs, r);
} else {
r = rt;
split(t[rt].ls, v, l, t[rt].ls);
}
push_up(rt);
}
int merge(int r1, int r2) {
if (!r1 or !r2)
return r1 | r2;
if (t[r1].rnd > t[r2].rnd) {
t[r1].rs = merge(t[r1].rs, r2);
push_up(r1);
return r1;
} else {
t[r2].ls = merge(r1, t[r2].ls);
push_up(r2);
return r2;
}
}
int newnode(int key, int rnd, int col) {
t[++idx] = {0, 0, 0, 1, key, rnd, col};
return idx;
}
int gf(int x) {
while (t[x].fa)
x = t[x].fa;
return x;
}
int query(int x) {
while (t[x].rs)
x = t[x].rs;
return t[x].col;
}
}
using namespace FHQ;
signed main() {
IOS;
cin >> n >> m >> q;
for (int i = 1; i <= n; i++)
root[i] = newnode(0, oo, i);
for (int i = 1; i <= q; i++) {
cin >> a[i].opt >> a[i].x;
if (a[i].opt == 1) {
cin >> a[i].y;
upd[a[i].x].push_back({i, 0});
upd[a[i].x + 1].push_back({i, 1});
}
}
for (int i = 1; i <= n; i++) {
sort(upd[i].begin(), upd[i].end(), cmp);
for (int j = 0; j < upd[i].size(); j++) {
int x = upd[i][j].fi;
if (j and a[x].y == a[upd[i][j - 1].fi].y)
continue;
int id = newnode(a[x].y, rnd(), i);
a[x].id[upd[i][j].se] = id;
root[i] = merge(root[i], id);
}
root[i] = merge(root[i], newnode(m + 1, rnd(), i));
}
for (int i = 1; i <= q; i++) {
if (a[i].opt == 1) {
int r1 = gf(a[i].id[0]), r2 = gf(a[i].id[1]);
int x, y, z, w;
split(r1, a[i].y, x, y);
split(r2, a[i].y, z, w);
root[r1] = merge(x, w);
root[r2] = merge(z, y);
} else
cout << query(a[i].x) << "\n";
}
return 0;
}