线段树(SegmentTree)

线段树

作用: 支持对一个数组进行高效的查询和修改
时间复杂度: 建树O(n) 查询和修改O(logn)
代码:

#include<iostream>
using namespace std;

#define int long long 
#define endl '\n'

// SegmentTree templete

const int N = 1000010;

int arr[N];
int sum[N << 2];
int add[N << 2];



//汇总左右孩子的和
void up(int i){
    sum[i] = sum[i << 1] + sum[i << 1 | 1];
}

//更新 sum 并添加懒信息
void lazy(int i,int v,int n){
    sum[i] += v * n;
    add[i] += v;
}

//下发懒信息并将自己的懒信息清零
void down(int i,int ln,int rn){
    if(add[i]!=0){
        lazy(i << 1,add[i],ln);
        lazy(i << 1 | 1,add[i],rn);
        add[i] = 0;
    }
}


//建树
void build(int l,int r,int i){
    if(l == r){
        sum[i] = arr[l];
    }
    else{
        int mid = (l + r) >> 1;
        build(l,mid,i << 1);
        build(mid+1,r,i << 1 | 1);
        up(i);
    }
    add[i] = 0;
}

//将jobl ~ jobr 中的每个数都添加 v,从 l r i 位置开始,初始时为 1, n , 1;
void Add(int jobl,int jobr,int v,int l,int r,int i){
    
    //全包含直接lazy
    if(l >= jobl && r <= jobr){
        lazy(i,v,r - l + 1);
    }
    else {
        int mid = (l+r) >> 1;
        
        //往下一层找,先将懒信息下发
        down(i,mid - l + 1,r - mid);

        //左边包含
        if(mid >= jobl){
            Add(jobl,jobr,v,l,mid,i << 1);
        }
        //右边包含
        if(mid < jobr){
            Add(jobl,jobr,v,mid+1,r,i << 1 | 1);
        }

        //汇总信息
        up(i);
    }
}

int query(int jobl,int jobr,int l,int r,int i){

    //全包直接返回和
    if(l >= jobl && r <= jobr){
        return sum[i];
    }
    else {
        int mid = (l + r) >> 1;

        //先下发懒信息
        down(i,mid - l + 1,r - mid);
        
        int ans = 0;
        if(mid >= jobl){
            ans += query(jobl,jobr,l,mid,i << 1);
        }
        if(mid < jobr){
            ans += query(jobl,jobr,mid+1,r,i<<1 | 1);
        }
        return ans;
    }
}


signed main(){

    int n,q;
    cin >> n >> q;
    for(int i = 1;i<=n;i++)cin >> arr[i];
    build(1,n,1);
    while(q--){
        int op;
        cin >> op;
        if(op == 1){
            int jobl,jobr,v;
            cin >> jobl >> jobr >> v;
            Add(jobl,jobr,v,1,n,1);
        }
        else if(op == 2){
            int jobl,jobr;
            cin >> jobl >> jobr;
            cout << query(jobl,jobr,1,n,1) << endl;
        }
    }


    return 0;
}

posted on 2026-08-14 09:35  Sean2299  阅读(4)  评论(0)    收藏  举报

导航