题解:P9358 [ICPC 2022 Xi'an R] Bridge

感谢 @Lgx_Q 大佬教导的 FHQ 做法。

前面的部分和题解区其它平衡树做法大致相同,将第一次到达某一列时所在的坐标写成一个序列,在 \((x,y)\) 建桥就相当于交换这两部分:

  • \((x,y)\) 所在序列中,\((x,y)\) 后面的部分;
  • \((x+1,y)\) 所在序列中,\((x+1,y)\) 后面的部分。

如图是样例前两次建桥后,对序列的影响,颜色代表 \(x\)

img

所以每一行都建立一个 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;
}
posted @ 2025-08-03 16:30  Garbage_fish  阅读(5)  评论(0)    收藏  举报