线段树模板

洛谷-线段树1模板

//入门代码 
#include<cstdio>
typedef long long ll;
using namespace std;

ll a[100005];
ll Seg[400005]={0},add[400005]={0};

int N,M;
inline void PushUp(int rt){Seg[rt]=Seg[rt<<1]+Seg[rt<<1|1];}

inline void Built(int l,int r,int rt){
    if(l==r){
        Seg[rt]=a[l];
        return;
    }
    int m = (l+r)>>1;
    Built(l,m,rt<<1);
    Built(m+1,r,rt<<1|1);
    
    PushUp(rt);
}
inline void Pushdown(int sizel,int sizer,int rt){
    add[rt<<1]+=add[rt];add[rt<<1|1]+=add[rt];
    Seg[rt<<1]+=add[rt]*sizel;Seg[rt<<1|1]+=add[rt]*sizer;
    add[rt]=0;
}
inline void Update(int L,int R,ll C,int l,int r,int rt){
    if(l>R||r<L)return;
    if(L<=l&&R>=r){
        add[rt]+=C;
        Seg[rt]+=C*(r-l+1);
        return;
    }
    
    int m = (r+l)>>1;
    Pushdown((m-l+1),(r-m),rt);
    
    if(L<=m)Update(L,R,C,l,m,rt<<1);
    if(R>m)Update(L,R,C,m+1,r,rt<<1|1);
    PushUp(rt);
}

inline ll query(int L,int R,int l,int r,int rt){
    
    if(l>R||r<L)return 0;
    if(L<=l&&R>=r){
        return Seg[rt];
    }
    int m = (l+r)>>1;
    Pushdown((m-l+1),(r-m),rt);
    
    ll ans = 0;
    if(L<=m)ans+=query(L,R,l,m,rt<<1);
    if(R>m)ans+=query(L,R,m+1,r,rt<<1|1);
    return ans;
} 
int main(){
    
    scanf("%d%d",&N,&M);
    for(register int i=1;i<=N;i++)scanf("%d",&a[i]);
    
    Built(1,N,1);
    
    int point,l,r,x;
    for(register int i=1;i<=M;i++){
        
        scanf("%d",&point);
        
        if(point==1){
            scanf("%d%d%d",&l,&r,&x);
            Update(l,r,x,1,N,1);
        }
        else{
            scanf("%d%d",&l,&r);
            printf("%lld\n",query(l,r,1,N,1));
        }
    }
    
    return 0;
}



2018.12.7更

看到了一种叫标记永久化的写法,即不需要下传标记,每次直接计算对答案的贡献即可,据说在可持久化数据结构中会更方便。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 100005
#define lson (rt<<1)
#define rson (rt<<1|1)
#define mid ((l+r)>>1)

long long seg[MAXN<<2],tag[MAXN<<2];
int N,M;

inline void pushup(int rt,int l,int r) {
	seg[rt] = seg[lson] + seg[rson] + tag[rt]*(r-l+1);
}

void Build(int rt,int l,int r) {
	tag[rt] = 0;
	if(l==r) {
		scanf("%lld",&seg[rt]);
		return;
	}
	Build(lson,l,mid);
	Build(rson,mid+1,r);
	pushup(rt,l,r);
}

void update(int L,int R,long long C,int rt,int l,int r) {
	if(L<=l&&R>=r) {
		tag[rt] += C;
		seg[rt] += (r-l+1)*C;
		return;
	}
	if(L>r||R<l) return;
	if(L<=mid) update(L,R,C,lson,l,mid);
	if(R>mid) update(L,R,C,rson,mid+1,r);
	pushup(rt,l,r);
}

long long query(int L,int R,int rt,int l,int r) {
	if(L<=l&&R>=r) return seg[rt];
	if(L>r||R<l) return 0;
	long long ans = tag[rt] * (std::min(r,R)-std::max(L,l)+1);
	if(L<=mid) ans += query(L,R,lson,l,mid);
	if(R>mid) ans += query(L,R,rson,mid+1,r);
	return ans;
}

int main() {

	scanf("%d%d",&N,&M);
	Build(1,1,N);

	int opt,l,r;
	long long k;

	for(int i=1;i<=M;++i) {

		scanf("%d%d%d",&opt,&l,&r);
		if(opt==1) {
			scanf("%lld",&k);
			update(l,r,k,1,1,N);
		}
		else printf("%lld\n",query(l,r,1,1,N));
	}

	return 0;
}

注意这里的pushup的改动,每次一定要计算上tag对本层的影响。

posted @ 2018-02-23 13:15  Neworld1111  阅读(128)  评论(0编辑  收藏  举报