线段树

0 阅读2分钟

应用:数组大批量相同重复操作。


#include<iostream>
#include<vector>

using namespace std;

const int MAXN=100005;
long long tree_sum[MAXN*4];
long long lazy_tag[MAXN*4];
long long arr[MAXN];

void push_up(int p){
    tree_sum[p]=tree_sum[p*2]+tree_sum[p*2+1];

}

void push_down(int p,int l,int r){
    if(lazy_tag[p]!=0){
        int mid=(l+r)/2;
        lazy_tag[p*2]+=lazy_tag[p];
        tree_sum[p*2]+=lazy_tag[p]*(mid-l+1);

        lazy_tag[p*2+1]+=lazy_tag[p];
        tree_sum[p*2+1]+=lazy_tag[p]*(r-mid);

        lazy_tag[p]=0;

    }


}

void build_tree(int p,int l,int r){
    lazy_tag[p]=0;
    if(l==r){
        tree_sum[p]=arr[l];
        return;
    }
    int mid=(l+r)/2;
    build_tree(p*2,l,mid);
    build_tree(p*2+1,mid+1,r);
    push_up(p);
}

void update_tree(int p,int l,int r,int ql,int qr,long long val){
    if(ql<=l&&r<=qr){
        tree_sum[p]+=val*(r-l+1);
        lazy_tag[p]+=val;
        return;
    }
    push_down(p,l,r);
    int mid=(l+r)/2;
    if(ql<=mid)update_tree(p*2,l,mid,ql,qr,val);
    if(qr>mid)update_tree(p*2+1,mid+1,r,ql,qr,val);
    push_up(p);
}

long long query_tree(int p,int l,int r,int ql,int qr){
    if(ql<=l&&r<=qr){
        return tree_sum[p];
    }
    push_down(p,l,r);
    int mid=(l+r)/2;
    long long total_sum=0;
    if(ql<=mid)total_sum+=query_tree(p*2,l,mid,ql,qr);
    if(qr>mid)total_sum+=query_tree(p*2+1,mid+1,r,ql,qr);
    return total_sum;

}
int main(){
    int n=5;
    for(int i=1;i<n;i++){
        arr[i]=i;
    }
    build_tree(1,1,n);
    cout<<"区间[2,4]的初试和:"<<query_tree(1,1,n,2,4)<<endl;
    update_tree(1,1,n,2,4,10);
    cout<<"区间【2,4】修改后的和"<<query_tree(1,1, n,2,4)<<endl;
    return 0;
}

要点解析:arr数组初始化后就被抛弃,所以每次修改并没有修改到底层。

image.png

同时,每次线段树是以区间为最小单位进行操作,并且每次操作只修改一层,清除本层的lazy_val后就推给下一层不管。只要区间符合条件就直接向上层汇报结果,不向下细分了。怎么说呢有点只可意会不可言传的味道。