暂存一下线段树模板

template <class Info>  // 模板类,Info 是一个模板参数,表示线段树节点存储的信息类型
struct SegmentTree {
    int n;              // 表示线段树中存储的元素个数
    vector<Info> info;  // 用于存储线段树节点的数组,类型为 Info

    SegmentTree() : n(0) {}  // 默认构造函数,初始化 n 为 0
    // 传入 n_ 表示元素个数,v_ 表示初始化的默认值
    SegmentTree(int n_, Info v_ = Info()) {
        init(n_, v_);
    }

    // 模板构造函数:传入一个向量,用于初始化线段树
    template <class T>
    SegmentTree(vector<T> init_) {
        init(init_);
    }

    // 初始化函数:传入元素个数和默认值
    void init(int n_, Info v_ = Info()) {
        init(vector(n_, v_));  // 用一个大小为 n_ 的向量初始化,元素值为 v_
    }

    // 模板初始化函数:传入一个向量,用于初始化线段树
    template <class T>
    void init(vector<T> init_) {
        n = init_.size();  // 记录元素个数
        // 初始化 info 数组的大小,4 << __lg(n) 是 2 的 log(n) 次方乘以 4
        info.assign(4 << __lg(n), Info());
        auto build = [&](auto self, int p, int l, int r) -> void {
            if (r - l == 1) {        // 如果区间长度为 1,说明是叶节点
                info[p] = init_[l];  // 将叶节点赋值为初始化向量的对应值
                return;
            }
            int m = (l + r) / 2;          // 计算区间中点
            self(self, 2 * p, l, m);      // 递归构建左子树
            self(self, 2 * p + 1, m, r);  // 递归构建右子树
            pushup(p);                    // 更新当前节点的值为其两个子节点的合并值
        };

        build(build, 1, 0, n);  // 调用 Lambda 函数,从根节点开始构建线段树
    }

    void pushup(int p) {
        info[p] = info[2 * p] + info[2 * p + 1];
    }
    void modify(int p, int l, int r, int x, const Info &v) {
        if (r - l == 1) {  // 如果区间长度为 1,说明是叶节点
            info[p] = v;   // 直接修改
            return;
        }
        int m = (l + r) / 2;
        if (x < m) {
            modify(2 * p, l, m, x, v);  // 递归修改左子树
        } else {
            modify(2 * p + 1, m, r, x, v);  // 递归修改右子树
        }
        pushup(p);  // 更新当前节点的值为其两个子节点的合并值
    }

    // 对外的修改接口,只需传入修改位置和新值
    void modify(int p, const Info &v) {
        modify(1, 0, n, p, v);  // 从根节点开始递归修改
    }

    // 区间查询函数:递归查询区间 [x, y) 的信息
    Info rangeQuery(int p, int l, int r, int x, int y) {
        if (l >= y || r <= x) {  // 如果查询区间与当前区间无交集
            return Info();       // 返回默认的 Info 对象
        }
        if (l >= x && r <= y) {  // 如果当前区间完全包含在查询区间内
            return info[p];      // 返回当前节点的值
        }
        int m = (l + r) / 2;  // 计算区间中点
        // 递归查询左子树和右子树,并合并结果
        return rangeQuery(2 * p, l, m, x, y) + rangeQuery(2 * p + 1, m, r, x, y);
    }

    // 对外的区间查询接口,传入区间 [l, r)
    Info rangeQuery(int l, int r) {
        return rangeQuery(1, 0, n, l, r);  // 从根节点开始查询
    }

    // 查找区间内第一个满足条件的元素
    template <class F>
    int findFirst(int p, int l, int r, int x, int y, F &&pred) {
        if (l >= y || r <= x) {  // 如果查询区间与当前区间无交集
            return -1;           // 返回 -1 表示未找到
        }
        if (l >= x && r <= y && !pred(info[p])) {  // 如果当前区间完全包含在查询区间内且不满足条件
            return -1;                             // 返回 -1 表示未找到
        }
        if (r - l == 1) {  // 如果区间长度为 1,说明是叶节点
            return l;      // 返回叶节点的位置
        }
        int m = (l + r) / 2;                           // 计算区间中点
        int res = findFirst(2 * p, l, m, x, y, pred);  // 递归查找左子树
        if (res == -1) {                               // 如果左子树未找到,继续查找右子树
            res = findFirst(2 * p + 1, m, r, x, y, pred);
        }
        return res;  // 返回结果
    }

    // 对外的查找接口,查找区间 [l, r) 内第一个满足条件的元素
    template <class F>
    int findFirst(int l, int r, F &&pred) {
        return findFirst(1, 0, n, l, r, pred);  // 从根节点开始查找
    }

    // 查找区间内最后一个满足条件的元素
    template <class F>
    int findLast(int p, int l, int r, int x, int y, F &&pred) {
        if (l >= y || r <= x) {  // 如果查询区间与当前区间无交集
            return -1;           // 返回 -1 表示未找到
        }
        if (l >= x && r <= y && !pred(info[p])) {  // 如果当前区间完全包含在查询区间内且不满足条件
            return -1;                             // 返回 -1 表示未找到
        }
        if (r - l == 1) {  // 如果区间长度为 1,说明是叶节点
            return l;      // 返回叶节点的位置
        }
        int m = (l + r) / 2;
        int res = findLast(2 * p + 1, m, r, x, y, pred);  // 递归查找右子树
        if (res == -1) {                                  // 如果右子树未找到,继续查找左子树
            res = findLast(2 * p, l, m, x, y, pred);
        }
        return res;  // 返回结果
    }

    // 对外的查找接口,查找区间 [l, r) 内最后一个满足条件的元素
    template <class F>
    int findLast(int l, int r, F &&pred) {
        return findLast(1, 0, n, l, r, pred);  // 从根节点开始查找
    }
};
posted @ 2024-10-30 02:40  potential-star  阅读(33)  评论(0)    收藏  举报