洛谷 P3372 【模板】线段树 1

题意: 区间更新区间查询

思路:直接线段树实现就行,难点还是手撕线段树的结构跟细节。 说一下merge:直接对两个区间的sum求和。applyLazy:lazy值*区间长度。

struct Node{
    bool is_lazy;
    long long sum = 0;
    long long lazy_val = 0;

    Node(): is_lazy(false){}

    Node operator + (const Node& other){
        Node res = *this;
        res.sum += other.sum;
        return res;
    }

    void operator |= (const Node& other){
        this->lazy_val += other.lazy_val;
        this->is_lazy = true;
    }

    void applyLazy(Node& lazy, int length){
        this->sum += lazy.lazy_val * length;
    }
};




template <typename T>
class SegmentTree{
public:
    SegmentTree(int sz): sz_(sz), flag_{}{
        st_.resize(4 * sz_);
        lazy_.resize(4 * sz_);
    }

    SegmentTree(const vector<T>& s): SegmentTree(int(s.size() - 1)){
        function<void(int, int, int)> build = [&](int p, int l, int r){
            if (l == r){
                st_[p] = s[l];
            }
            else{
                int mid = (l + r) >> 1;
                build(p << 1, l, mid);
                build(p << 1 | 1, mid + 1, r);
                st_[p] = merge(st_[p << 1], st_[p << 1 | 1]);
            }
        };
        build(1, 1, sz_);
    }

    void update(int i, int j, T val){
        update(1, 1, sz_, i, j, val);
    }

    T query(int i, int j){
        return query(1, 1, sz_, i, j);
    }


private:
    int sz_;
    vector<T> st_;
    vector<T> lazy_;
    const T flag_;

    T merge(T a, T b){
        return a + b;
    }

    void pushDown(int p, int l, int r){
        if (lazy_[p].is_lazy){
            st_[p].applyLazy(lazy_[p], r - l + 1);
            if (l != r){
                lazy_[p << 1] |= lazy_[p];
                lazy_[p << 1 | 1] |= lazy_[p];
            }
            lazy_[p] = flag_;
        }
    }

    void update(int p, int l, int r, int i, int j, T val){
        pushDown(p, l, r);
        if (i > j){
            return;
        }
        if (l >= i && r <= j){
            lazy_[p] = val;
            lazy_[p].is_lazy = true;
            pushDown(p, l, r);
        }
        else{
            int mid = (l + r) >> 1;
            update(p << 1, l, mid, i, min(mid, j), val);
            update(p << 1 | 1, mid + 1, r, max(i, mid + 1), j, val);
            st_[p] = merge(st_[p << 1], st_[p << 1 | 1]);
        }
    }

    T query(int p, int l, int r, int i, int j){
        pushDown(p, l, r);
        if (l >= i && r <= j){
            return st_[p];
        }
        int mid = (l + r) >> 1;
        if (j <= mid){
            return query(p << 1, l, mid, i, j);
        }
        else if (i > mid){
            return query(p << 1 | 1, mid + 1, r, i, j);
        }
        return merge(query(p << 1, l, mid, i, mid), query(p << 1 | 1, mid + 1, r, mid + 1, j));
    }
};


void solve(){
    int n, q;
    cin >> n >> q;

    vector<Node> a(n + 1);
    for (int i = 1; i <= n; ++i){
        cin >> a[i].sum;
    }
    SegmentTree<Node> st(a);

    while (q --){
        int t;
        cin >> t;
        int x, y;
        cin >> x >> y;
        if (t & 1){
            Node k;
            cin >> k.lazy_val;
            st.update(x, y, k);
        }
        else{
            cout << st.query(x, y).sum << '\n';
        }
    }
}

总结:
1 build里面忘记合并子区间。
2 query忘记写返回值
3 |=重载多写了返回值,导致lazy_val没有有向下传递到子区间

感觉在空间复杂度上还可以优化,室友有更好的存储lazy值的方式

posted @   _Yxc  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
点击右上角即可分享
微信分享提示