2

考虑这样一个问题:在字符串的前面插入字符,动态查询后缀排序的结果。

考虑用平衡树维护。那么我们需要 \(O(1)\) 地比较两个后缀 \(s[i\dots n]\)\(s[j\dots n]\) 的大小关系。

首先如果 \(s_i\not =s_j\) 就结束了。否则只需比较 \(s[i+1\dots n]\)\(s[j+1\dots n]\) 即可。这两个后缀都已经被插入平衡树了。

考虑给平衡树上的每个节点都赋两个权值 \((l,r)\),一个节点的左右儿子的两个权值分别是 \((l,\frac{l+r}{2})\)\((\frac{l+r}{2},r)\)。那么树上两个节点的大小关系就是 \(l+r\) 的大小关系。于是可以 \(O(1)\) 比较了。

注意到 \((l,r)\) 的信息是自顶向下转移的。所以我们使用的平衡树既不能是基于旋转的,也不能是基于分裂的。使用 \(\frac{1}{sz}\) 平衡树,即对于在插入/删除过程中经过的每一个节点,都以其 \(\frac{1}{sz}\) 的概率将其整棵子树重构。可以证明这样做的树高是 \(\log\) 的。

由于树高是期望 \(\log\) 而非严格 \(\log\),所以存权值不能用 long long 类型,要用 double。

模板题代码,但是被卡常
#include<bits/stdc++.h>
using namespace std;
const int maxn = 800005;
int n, m, msk, res;
string s;
stack<int> st;
int pre[maxn];
mt19937 rnd(time(0));
string decode(string s, int msk) {
    for (int i = 0; i < s.size(); i++) {
        msk = (msk * 131 + i) % s.size();
        swap(s[i], s[msk]);
    }
    return s;
}
struct HeigeTree {
    int sz[maxn], p[maxn], son[maxn][2], rt, cnt;
    double x[maxn], y[maxn];
    vector<int> tmp;
    void pushup(int k) {sz[k] = sz[son[k][0]] + sz[son[k][1]] + p[k];}
    int new_node(double l, double r, int id) {sz[id] = p[id] = 1; x[id] = l, y[id] = r; return id;}
    bool cmp(int a, int b) {
        if (s[a] < s[b]) return 1;
        if (s[a] > s[b]) return 0;
        return x[pre[a]] + y[pre[a]] < x[pre[b]] + y[pre[b]];
    }
    bool cmp(int p, string t) {
        for (int i = 0; i < t.size(); i++) {
            if (!p || s[p] < t[i]) return 1;
            if (s[p] > t[i]) return 0;
            p = pre[p];
        }
        return 0;
    }
    void dfs(int k) {
        if (!k) return;
        dfs(son[k][0]);
        tmp.push_back(k);
        dfs(son[k][1]);
    }
    int build(int l, int r, double L, double R) {
        if (l > r) return 0;
        int mid = l + r >> 1; int k = tmp[mid]; x[k] = L, y[k] = R;
        son[k][0] = build(l, mid - 1, L, (L + R) / 2); son[k][1] = build(mid + 1, r, (L + R) / 2, R);
        pushup(k);
        return k;
    }
    int rebuild(int k, double l, double r) {tmp.clear(); dfs(k); return build(0, (int)tmp.size() - 1, l, r);}
    int ins(int k, int v, double l, double r) {
        if (!k) return new_node(l, r, v);
        if (cmp(v, k)) son[k][0] = ins(son[k][0], v, l, (l + r) / 2);
        else son[k][1] = ins(son[k][1], v, (l + r) / 2, r);
        pushup(k);
        if (rnd() % (sz[k] + 1) == 0) return rebuild(k, x[k], y[k]);
        return k;
    }
    int del(int k, int v) {
        sz[k]--;
        if (k == v) {p[k] = 0; return k;}
        if (x[v] + y[v] < x[k] + y[k]) son[k][0] = del(son[k][0], v);
        else son[k][1] = del(son[k][1], v);
        if (rnd() % (sz[k] + 1) == 0) return rebuild(k, x[k], y[k]);
        return k;
    }
    int qry(int k, string s) {
        if (!k) return 0;
        if (cmp(k, s)) return qry(son[k][1], s) + sz[son[k][0]] + p[k];
        else return qry(son[k][0], s);
    }
    int query(string s) {
        int sum = qry(rt, s);
        s.back()++;
        return qry(rt, s) - sum;
    }
} T;
signed main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cin >> n >> s; s = " " + s;
    st.push(0);
    for (int i = 1; i < s.size(); i++) {
        pre[i] = i - 1; st.push(i);
        T.rt = T.ins(T.rt, i, 0, 1e9);
        assert(T.p[i]);
    }
    m = s.size() - 1;
    for (int i = 1; i <= n; i++) {
        string p; cin >> p;
        if (p == "QUERY") {
            string s; cin >> s; s = decode(s, msk); reverse(s.begin(), s.end());
            cout << (res = T.query(s)) << '\n';
            msk ^= res;
        }
        else if (p == "ADD") {
            string t; cin >> t; t = decode(t, msk);
            for (int j = 0; j < t.size(); j++) {
                s += t[j]; pre[++m] = st.top(); st.push(m);
                T.rt = T.ins(T.rt, m, 0, 1e9);
            }
        }
        else {
            assert(p == "DEL");
            int x; cin >> x;
            for (int j = 0; j < x; j++) {
                T.rt = T.del(T.rt, st.top());
                st.pop();
            }
        }
    }
    return 0;
}
posted @ 2025-08-23 17:11  Egg_eating_master  阅读(32)  评论(0)    收藏  举报