静态主席树模板

已通过洛谷【模板1】【模板2区间第k小】
【区间小于x的个数-牛客】【区间小于x的个数-代码源
杭电4417怀疑数据可能有问题(?,调了一下午没调出来,如有大佬改出来了麻烦告知下错哪了qwq

/* 可持久化线段树(主席树)模板
 * @tparam Node: 节点结构体类型,需包含左右子节点和值
 * 功能:支持单点更新、单点查询、区间第k小查询、排名查询
 */
template<class Node>
struct PersistentSegmentTree {
    const int n;         // 值域大小(离散化后的值域范围)
    int tot = 0;         // 节点计数器
    vector<Node> tr;     // 节点存储池
    vector<int> root;    // 各版本根节点

    PersistentSegmentTree() : n(0) {}
    PersistentSegmentTree(int n_) : n(n_) {
        tr.reserve((n << 7) + 10);
        root.reserve(n + 10);
        tr.resize(2);          // 初始空树占位
        root.push_back(1);          // 版本0的根节点
        init(vector<int>(n)); //建空树
    }
    void init(vector<int> _init) {
        function<void(int&, int, int)> build = [&](int& now, int l, int r) {
            now = ++ tot;
            if (l == r) {
                tr[now].v = _init[l - 1];
                return ;
            }
            int m = (l + r) >> 1;
            build(tr[now].l, l, m);
            build(tr[now].r, m + 1, r);
            tr[now].v = tr[tr[now].l].v + tr[tr[now].r].v;
        };
        build(root[0], 1, n);
    }
    // 在指定版本基础上更新
    // @param last: 基础版本根节点
    // @param pos:  要更新的位置(离散化后的值)
    // @param w:    更新值
    // @return:     新版本索引
    int update(int last, int pos, int w) {
        assert(last < root.size());
        int new_root = ++tot;
        root.push_back(new_root);
        insert(root[last], new_root, 1, n, pos, w);
        return (int)root.size() - 1;
    }
    // 查询指定版本的单点值
    int query(int version, int pos) {
        return query(root[version], 1, n, pos);
    }
    /* 区间第k小查询
     * @param l_root: 区间左端点前一个版本的根
     * @param r_root: 区间右端点版本的根
     * @param k:      要查询的排名
     * 时间复杂度: O(log n)
     */
    int query_kth(int l_root, int r_root, int k) {
        return query_kth(root[l_root - 1], root[r_root], 1, n, k);
    }
    /* 区间内小于x的数的个数(排名)
     * @param l_root: 区间左端点前一个版本的根
     * @param r_root: 区间右端点版本的根
     * @param x:      查询值
     * 时间复杂度: O(log n)
     */
    int query_rank(int l_root, int r_root, int x) {
        return query_rank(root[l_root - 1], root[r_root], 1, n, x);
    }
  private:
    // 插入操作
    void insert(int last, int now, int l, int r, int pos, int w) {
        tr[now] = tr[last];
        if (l == r) {
            tr[now].v += w;
            return;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            tr[now].l = ++tot;
            insert(tr[last].l, tr[now].l, l, mid, pos, w);
        }
        else {
            tr[now].r = ++tot;
            insert(tr[last].r, tr[now].r, mid + 1, r, pos, w);
        }
        tr[now].v = tr[tr[now].l].v + tr[tr[now].r].v;
    }
    // 单点查询
    int query(int now, int l, int r, int pos) {
        if (l == r) {
            return tr[now].v;
        }
        int mid = (l + r) >> 1;
        if (pos <= mid) {
            return query(tr[now].l, l, mid, pos);
        }
        else {
            return query(tr[now].r, mid + 1, r, pos);
        }
    }
    // 查询第k小
    int query_kth(int last, int now, int l, int r, int k) {
        if (l == r) {
            return l;    // 叶子节点即为答案
        }
        int mid = (l + r) >> 1;
        int left_count = tr[tr[now].l].v - tr[tr[last].l].v; // 左子树元素个数
        if (k <= left_count) {
            return query_kth(tr[last].l, tr[now].l, l, mid, k);
        }
        else {
            return query_kth(tr[last].r, tr[now].r, mid + 1, r, k - left_count);
        }
    }
    // 查询排名(小于x的元素个数)
    int query_rank(int last, int now, int l, int r, int x) {
        if (x < l) {
            return 0;    // x小于当前区间,返回0
        }
        if (r < x) {
            return tr[now].v - tr[last].v;    // x大于当前区间,返回整个区间元素数
        }
        if (l == r) {
            return 0;
        }
        int mid = (l + r) >> 1;
        int left_rank = query_rank(tr[last].l, tr[now].l, l, mid, x);
        int right_rank = query_rank(tr[last].r, tr[now].r, mid + 1, r, x);
        return left_rank + right_rank;
    }
};

struct Node {
    int l, r, v;
    Node(): l(0), r(0), v(0) {}
};
posted @ 2024-08-07 19:42  Ke_scholar  阅读(30)  评论(2)    收藏  举报