线段树模板

线段树是一种支持区间修改和区间查询的数据结构, 详细介绍可以参考算法学习笔记(14): 线段树, 下面记录几种使用过的模板:

  • 区间加+查询区间求和
  • 区间更新+查询区间极小值
  • 区间加+查询区间极小值

注意模板线段树函数中的下标都是从1开始, 用于初始化的数组下标从0开始

区间加+查询区间求和

cpp 复制代码
class SegmentTree {
public:
    typedef long long ll;

    inline void push_down(ll index) {
        st[index << 1].lazy = 1;
        st[index << 1 | 1].lazy = 1;
        st[index << 1].mark += st[index].mark;
        st[index << 1 | 1].mark += st[index].mark;
        st[index << 1].s += st[index].mark * (st[index << 1].tr - st[index << 1].tl + 1);
        st[index << 1 | 1].s += st[index].mark * (st[index << 1 | 1].tr - st[index << 1 | 1].tl + 1);

        st[index].lazy = 0;
        st[index].mark = 0;
    }

    inline void push_up(ll index) {
        st[index].s = st[index << 1].s + st[index << 1 | 1].s;
    }

    SegmentTree(vector<int> &init_list) {
        st = vector<SegmentTreeNode>(init_list.size() * 4 + 10);
        build(init_list, 1, init_list.size());
    }

    void build(vector<int> &init_list, ll l, ll r, ll index = 1) {
        st[index].tl = l;
        st[index].tr = r;
        st[index].lazy = 0;
        st[index].mark = 0;
        if (l == r) {
            st[index].s = init_list[l - 1];
        } else {
            ll mid = (l + r) >> 1;
            build(init_list, l, mid, index << 1);
            build(init_list, mid + 1, r, index << 1 | 1);
            push_up(index);
        }
    }

    void add(ll l, ll r, ll d, ll index = 1) {
        if (l > st[index].tr or r < st[index].tl)
            return;
        else if (l <= st[index].tl and st[index].tr <= r) {
            st[index].s += (st[index].tr - st[index].tl + 1) * d;
            st[index].mark += d;
            st[index].lazy = 1;
        } else {
            if (st[index].lazy)
                push_down(index);
            add(l, r, d, index << 1);
            add(l, r, d, index << 1 | 1);
            push_up(index);
        }
    }

    ll query(ll l, ll r, ll index = 1) {
        if (l <= st[index].tl and st[index].tr <= r) {
            return st[index].s;
        } else {
            if (st[index].lazy)
                push_down(index);
            if (r <= st[index << 1].tr)
                return query(l, r, index << 1);
            else if (l > st[index << 1].tr)
                return query(l, r, index << 1 | 1);
            return query(l, r, index << 1) + query(l, r, index << 1 | 1);
        }
    }

private:
    struct SegmentTreeNode {
        ll tl;
        ll tr;
        ll s;
        ll mark;
        int lazy;
    };
    vector<SegmentTreeNode> st;
};

区间更新+查询区间极小值

这里的区间更新等效于执行这样的操作: l i [ k ] = m i n ( l i [ k ] , v a l ) , l e f t ≤ k ≤ r i g h t li[k]=min(li[k],val) , left \le k \le right li[k]=min(li[k],val),left≤k≤right

cpp 复制代码
class SegmentTree {
public:
    typedef long long ll;

    inline void push_down(ll index) {
        st[index << 1].lazy = 1;
        st[index << 1 | 1].lazy = 1;
        st[index << 1].mark = min(st[index << 1].mark, st[index].mark);
        st[index << 1 | 1].mark = min(st[index << 1 | 1].mark, st[index].mark);
        st[index << 1].s = min(st[index << 1].s, st[index].mark);
        st[index << 1 | 1].s = min(st[index << 1 | 1].s, st[index].mark);
        st[index].lazy = 0;
    }

    inline void push_up(ll index) {
        st[index].s = min(st[index << 1].s, st[index << 1 | 1].s);
    }

    SegmentTree(vector<int> &init_list) {
        st = vector<SegmentTreeNode>(init_list.size() * 4 + 10);
        build(init_list, 1, init_list.size());
    }

    void build(vector<int> &init_list, ll l, ll r, ll index = 1) {
        st[index].tl = l;
        st[index].tr = r;
        st[index].lazy = 0;
        st[index].mark = INT64_MAX;
        if (l == r) {
            st[index].s = init_list[l - 1];
        } else {
            ll mid = (l + r) >> 1;
            build(init_list, l, mid, index << 1);
            build(init_list, mid + 1, r, index << 1 | 1);
            push_up(index);
        }
    }

    void modify(ll l, ll r, ll val, ll index = 1) {
        if (l > st[index].tr or r < st[index].tl)
            return;
        else if (l <= st[index].tl and st[index].tr <= r) {
            st[index].s = min(st[index].s, val);
            st[index].mark = min(val, st[index].mark);
            st[index].lazy = 1;
        } else {
            if (st[index].lazy)
                push_down(index);
            modify(l, r, val, index << 1);
            modify(l, r, val, index << 1 | 1);
            push_up(index);
        }
    }

    ll query(ll l, ll r, ll index = 1) {
        if (l <= st[index].tl and st[index].tr <= r) {
            return st[index].s;
        } else {
            if (st[index].lazy)
                push_down(index);
            if (r <= st[index << 1].tr)
                return query(l, r, index << 1);
            else if (l > st[index << 1].tr)
                return query(l, r, index << 1 | 1);
            return min(query(l, r, index << 1), query(l, r, index << 1 | 1));
        }
    }

private:
    struct SegmentTreeNode {
        ll tl;
        ll tr;
        ll s;
        ll mark;
        int lazy;
    };
    vector<SegmentTreeNode> st;
};

区间加+查询区间极小值

cpp 复制代码
class SegmentTree {
public:
    typedef long long ll;

    inline void push_down(ll index) {
        st[index << 1].lazy = 1;
        st[index << 1 | 1].lazy = 1;
        st[index << 1].mark += st[index].mark;
        st[index << 1 | 1].mark += st[index].mark;
        st[index << 1].s += st[index].mark;
        st[index << 1 | 1].s += st[index].mark;
        st[index].lazy = 0;
        st[index].mark = 0;
    }

    inline void push_up(ll index) {
        st[index].s = min(st[index << 1].s, st[index << 1 | 1].s);
    }

    SegmentTree(vector<int> &init_list) {
        st = vector<SegmentTreeNode>(init_list.size() * 4 + 10);
        build(init_list, 1, init_list.size());
    }

    void build(vector<int> &init_list, ll l, ll r, ll index = 1) {
        st[index].tl = l;
        st[index].tr = r;
        st[index].lazy = 0;
        st[index].mark = INT64_MAX;
        if (l == r) {
            st[index].s = init_list[l - 1];
        } else {
            ll mid = (l + r) >> 1;
            build(init_list, l, mid, index << 1);
            build(init_list, mid + 1, r, index << 1 | 1);
            push_up(index);
        }
    }

    void add(ll l, ll r, ll d, ll index = 1) {
        if (l > st[index].tr or r < st[index].tl)
            return;
        else if (l <= st[index].tl and st[index].tr <= r) {
            st[index].s += d;
            st[index].mark += d;
            st[index].lazy = 1;
        } else {
            if (st[index].lazy)
                push_down(index);
            add(l, r, d, index << 1);
            add(l, r, d, index << 1 | 1);
            push_up(index);
        }
    }

    ll query(ll l, ll r, ll index = 1) {
        if (l <= st[index].tl and st[index].tr <= r) {
            return st[index].s;
        } else {
            if (st[index].lazy)
                push_down(index);
            if (r <= st[index << 1].tr)
                return query(l, r, index << 1);
            else if (l > st[index << 1].tr)
                return query(l, r, index << 1 | 1);
            return min(query(l, r, index << 1), query(l, r, index << 1 | 1));
        }
    }

private:
    struct SegmentTreeNode {
        ll tl;
        ll tr;
        ll s;
        ll mark;
        int lazy;
    };
    vector<SegmentTreeNode> st;
};
相关推荐
ChoSeitaku4 分钟前
链表循环及差集相关算法题|判断循环双链表是否对称|两循环单链表合并成循环链表|使双向循环链表有序|单循环链表改双向循环链表|两链表的差集(C)
c语言·算法·链表
娅娅梨6 分钟前
C++ 错题本--not found for architecture x86_64 问题
开发语言·c++
兵哥工控10 分钟前
MFC工控项目实例二十九主对话框调用子对话框设定参数值
c++·mfc
Fuxiao___13 分钟前
不使用递归的决策树生成算法
算法
我爱工作&工作love我18 分钟前
1435:【例题3】曲线 一本通 代替三分
c++·算法
娃娃丢没有坏心思1 小时前
C++20 概念与约束(2)—— 初识概念与约束
c语言·c++·现代c++
lexusv8ls600h1 小时前
探索 C++20:C++ 的新纪元
c++·c++20
lexusv8ls600h1 小时前
C++20 中最优雅的那个小特性 - Ranges
c++·c++20
白-胖-子1 小时前
【蓝桥等考C++真题】蓝桥杯等级考试C++组第13级L13真题原题(含答案)-统计数字
开发语言·c++·算法·蓝桥杯·等考·13级
workflower1 小时前
数据结构练习题和答案
数据结构·算法·链表·线性回归