线段树

支持区间修改和区间查询的线段树

2019-08-04  本文已影响0人  学无止境1980

这种线段树支持区间修改和区间查询,区间修改的操作通过懒惰标记(lazy tag)实现。

一道支持区间修改和区间查询的线段树的模板题:Luogu P3372 【模板】线段树 1。下面附上AC代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int MAXN=400010;
struct Node{
    int l,r,ls,rs;
    long long c,s;
}T[MAXN];
int cnt=0,x[MAXN];
int build(int l,int r){
    int t=cnt++;
    T[t]=(Node){l,r,-1,-1,0ll,0ll};
    if(l<r){
        int mid=(l+r)>>1;
        T[t].ls=build(l,mid);
        T[t].rs=build(mid+1,r);
        T[t].s=T[T[t].ls].s+T[T[t].rs].s;
    }
    else T[t].s=x[l];
    return t;
}
void pushdown(int v){
    if(T[v].c){
        if(T[v].l<T[v].r){
            T[T[v].ls].c+=T[v].c;
            T[T[v].ls].s+=(T[T[v].ls].r-T[T[v].ls].l+1)*T[v].c;
            T[T[v].rs].c+=T[v].c;
            T[T[v].rs].s+=(T[T[v].rs].r-T[T[v].rs].l+1)*T[v].c;
        }
        T[v].c=0;
    }
}
void change(int v,int l,int r,int c){
    pushdown(v);
    if(l<=T[v].l && T[v].r<=r){
        T[v].c+=c;
        T[v].s+=(T[v].r-T[v].l+1)*c;
        return;
    }
    if(l>T[v].r || r<T[v].l) return;
    change(T[v].ls,l,r,c);
    change(T[v].rs,l,r,c);
    T[v].s=T[T[v].ls].s+T[T[v].rs].s;
}
long long query(int v,int l,int r){
    if(l<=T[v].l && T[v].r<=r) return T[v].s;
    if(l>T[v].r || T[v].l>r) return 0;
    pushdown(v);
    return query(T[v].ls,l,r)+query(T[v].rs,l,r);
}
int main(){
    int N, M;
    scanf("%d%d",&N, &M);
    for(int i=0;i<N;i++) scanf("%d",&x[i]);
    int root=build(0,N-1);
    while(M--){
        int t; scanf("%d",&t);
        if(t==1){
            int l,r,c; 
            scanf("%d%d%d",&l,&r,&c);
            change(root,l-1,r-1,c);
        }
        else{
            int l,r; scanf("%d%d",&l,&r);
            printf("%lld\n",query(root,l-1,r-1));
        }
    }
    return 0;
}
上一篇 下一篇

猜你喜欢

热点阅读