BZOJ 3600. 没有人的算术


这道题的难处就在于快速对两个“数”进行比较,若能快速对两个“数”进行比较,查询操作用线段树维护即可。
陈立杰13年论文《重量平衡树和后缀平衡树在信息学奥赛中的应用》提到了一种用重量平衡树维护一个序列的方法。
平衡树上每个节点代表一个实数区间,若一个节点代表的区间为 $(l,r)$, 则其左儿子所代表的区间为 $(l, \dfrac{l+r}{2})$,右儿子所代表的区间为 $(\dfrac{l+r}{2}, r)$。而每个节点的值定义为 $\dfrac{l+r}{2}$,这样就能快速比较两个节点的值。而使用重量平衡树重构时对于这部分编码没有额外消耗,所以均摊复杂度仍为期望 $O(\log n)$。
修改操作即为产生一个新的“数”,在平衡树上插入,并对线段树对应节点进行修改。

#include 
using db = double;

namespace IO {
    const int bufl = 1 << 15;
    char buf[bufl], *s = buf, *t = buf;
    inline int fetch() {
        if (s == t) {t = (s = buf) + fread(buf, 1, bufl, stdin); if (s == t)return EOF;}
        return *s++;
    }
    inline int read_i() {
        int a = 0, b = 1, c = fetch();
        while (!isdigit(c))b ^= c == '-', c = fetch();
        while (isdigit(c))a = a * 10 + c - 48, c = fetch();
        return b ? a : -a;
    }
    inline int read_c() {
        int c = fetch();
        while (c <= 32 && c != EOF)c = fetch();
        return c;
    }
} using namespace IO;

const int N = 5e5 + 7;
const db alpha = 0.75;
db f[N];

struct Node {
    int l, r;
    Node(int _ = 0, int __ = 0): l(_), r(__) {}
    bool operator < (const Node &p) const {
        if (f[l] == f[p.l]) return f[r] < f[p.r];
        return f[l] < f[p.l];
    }
    bool operator == (const Node &p) const {
        return f[l] == f[p.l] && f[r] == f[p.r];
    }
};

int root, highest, n, m;

struct Tzy {
    Node a[N];
    int sz[N], ch[N][2], tol;
    int newnode(Node p) {
        sz[++tol] = 1;
        a[tol] = p;
        return tol;
    }
    inline void pushup(int x) {
        sz[x] = sz[ch[x][0]] + sz[ch[x][1]] + 1;
    }
    std::vector<int> vec;
    void dfs(int x) {
        if (!x) return;
        dfs(ch[x][0]);
        vec.push_back(x);
        dfs(ch[x][1]);
    }
    void build(int &x, int l, int r, db fl, db fr) {
        if (l > r) { x = 0; return; }
        int mid = l + r >> 1; db m = (fl + fr) * 0.5;
        x = vec[mid]; f[x] = m;
        build(ch[x][0], l, mid - 1, fl, m);
        build(ch[x][1], mid + 1, r, m, fr);
        pushup(x);
    }
    void rebuild(int &u, db l, db r) {
        vec.clear();
        dfs(u);
        build(u, 0, vec.size() - 1, l, r);
    }
    int insert(int &x, Node p, db fl, db fr) {
        db m = (fl + fr) * 0.5;
        if (!x) {
            x = newnode(p);
            f[x] = m;
            return x;
        }
        int cur;
        if (p == a[x]) {
            cur = x;
        } else {
            sz[x]++;
            if (p < a[x]) cur = insert(ch[x][0], p, fl, m);
            else cur = insert(ch[x][1], p, m, fr);
        }
        if ((db)(sz[x] * alpha) < (db)(std::max(sz[ch[x][0]], sz[ch[x][1]]))) {
            highest = x;
        } else {
            if (highest) {
                if (highest == ch[x][0])
                    rebuild(ch[x][0], fl, m);
                else
                    rebuild(ch[x][1], m, fr);
                highest = 0;
            }
        }
        return cur;
    }
} tzy;

int pos[N];

struct Seg {
#define lp p << 1
#define rp p << 1 | 1
    int tree[N << 2];
    inline int max(int a, int b) {
        if (f[pos[a]] >= f[pos[b]]) return a;
        return b;
    }
    inline void pushup(int p) {
        tree[p] = max(tree[lp], tree[rp]);
    }
    inline void update(int p, int l, int r, int pos) {
        if (l == r) {
            tree[p] = l;
            return;
        }
        int mid = l + r >> 1;
        if (pos <= mid) update(lp, l, mid, pos);
        else update(rp, mid + 1, r, pos);
        pushup(p);
    }
    inline int query(int p, int l, int r, int x, int y) {
        if (x <= l && y >= r) return tree[p];
        int mid = l + r >> 1;
        int ans = 0;
        if (x <= mid) ans = max(ans, query(lp, l, mid, x, y));
        if (y > mid) ans = max(ans, query(rp, mid + 1, r, x, y));
        return ans;
    }
    void build(int p, int l, int r) {
        if (l == r) {
            tree[p] = l;
            return;
        }
        int mid = l + r >> 1;
        build(lp, l, mid);
        build(rp, mid + 1, r);
        pushup(p);
    }
} seg;

int main() {
    n = read_i(), m = read_i();
    tzy.insert(root, Node(0, 0), 0, 1);
    f[0] = -1;
    for (int i = 1; i <= n; i++)
        pos[i] = 1;
    seg.build(1, 1, n);
    for (int l, r, k; m--; ) {
        char ch = read_c();
        l = read_i(), r = read_i();
        if (ch == 'C') {
            k = read_i();
            highest = 0;
            pos[k] = tzy.insert(root, Node(pos[l], pos[r]), 0, 1);
            if (highest)
                tzy.rebuild(root, 0, 1);
            seg.update(1, 1, n, k);
        } else {
            printf("%d\n", seg.query(1, 1, n, l, r));
        }
    }
    return 0;
}
View Code

 

你可能感兴趣的:(BZOJ 3600. 没有人的算术)