【模板】线段树 && 【题解】洛谷P3372

线段树(英语:Segment tree)是一种二叉树形数据结构,1977年由Jon Louis Bentley发明[1],用以储存区间线段,并且允许快速查询结构内包含某一点的所有区间。 一个包含n个区间的线段树,空间复杂度为O(nlogn),查询的时间复杂度则为O(log n+k),其中k是符合条件的区间数量。

——摘自维基百科

显然,当我们需要进行区间查询时,n^2算法无疑是最容易想到的,但也是效率最低的,所以用线段树可以用更短的时间来进行查询和修改。

具体思路分析见本题题解

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;

ll a[100005];          //存储原始数组
class Segment_Tree{
public:
    ll node[100005];           //存放节点编号
    ll tag[100005];            //存放懒惰标记
public:
//    Segment_Tree(){
//        node = new ll[400005];
//        tag = new ll[400005];
//    }
//
//    Segment_Tree(int size){
//        node = new ll [2*size+1];
//        tag = new ll[2*size+1];
//    }

    inline ll left_child(ll p){
        return 2*p;
    }

    inline ll right_child(ll p){
        return 2*p+1;
    }

    void push_up(ll p){         //向上维护区间和
        node[p] = node[left_child(p)] + node[right_child(p)];
    }

    void build(ll l, ll r, ll p){
        tag[p] = 0;
        if(l == r){
            node[p] = a[l];
            return;
        }
        ll mid = (l+r)/2;
        build(l,mid,left_child(p));
        build(mid+1,r,right_child(p));
        push_up(p);
    }

    void edit(ll l, ll r, ll p, ll k){        //修改p
        tag[p] += k;
        node[p] += (r-l+1)*k;
    }

    void push_down(ll l, ll r, ll p){       //向下维护懒惰标记
        ll mid = (l+r)/2;
        edit(l,mid,left_child(p),tag[p]);
        edit(mid+1,r,right_child(p),tag[p]);
        tag[p] = 0;          //归零
    }

    void update(ll nl, ll nr, ll l, ll r, ll p, ll k){
        //nl,nr为需要修改的区间
        if(nl <= l && r <= nr){     //[l,r]包含在[nl,nr]内,则直接修改即可
            node[p] += (r-l+1)*k;
            tag[p] += k;
            return;
        }
        push_down(l,r,p);
        ll mid = (l+r)/2;
        if(nl <= mid)
            update(nl, nr, l, mid, left_child(p), k);
        if(nr >= mid+1)
            update(nl, nr, mid+1, r, right_child(p), k);
        push_up(p);
    }

    ll search(ll nl, ll nr, ll l, ll r, ll p){
        //nl,nr为需要查询的区间
        if(nl <= l && nr >= r){
            return node[p];
        }
        ll mid = (l+r)/2;
        push_down(l,r,p);
        ll x = 0;
        if(nl <= mid)
            x += search(nl,nr,l,mid,left_child(p));
        if(nr >= mid+1)
            x += search(nl,nr,mid+1,r,right_child(p));
        return x;
    }
};

int main()
{
    int m,n;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        scanf("%lld",&a[i]);
    }
    Segment_Tree st;
    st.build(1,n,1);
    int x;
    ll a,b,c,d,e;
    for (int i = 0; i < m; ++i) {
        scanf("%d",&x);
        if(x == 1){
            scanf("%lld %lld %lld", &a, &b, &c);
            st.update(a,b,1,n,1,c);
        }
        else{
            scanf("%lld %lld", &d, &e);
            ll x = st.search(d,e,1,n,1);
            printf("%lld\n",x);
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_30115697/article/details/81839307