线段树板子

最近学到线段树,于是就写了个板子.

#include<cstdio>
struct node{
	int L,R;
	long long add,sum;
	void Add(int t){
		sum+=t*(R-L+1);
		add+=t;
	}
};
struct Segmenttree{
	node tree[400005];//注意要开四倍的数组
	int A[400005];
	void Up(int p){
		tree[p].sum=tree[p<<1].sum+tree[p<<1|1].sum;
	}
	void Down(int p){
		long long&t=tree[p].add;
		if(!t)return;
		tree[p<<1].Add(t);
		tree[p<<1|1].Add(t);
		t=0;
	}
	void Build(int L,int R,int p){
		tree[p].L=L,tree[p].R=R;
		if(L==R){
			tree[p].sum=A[L];
			return;
		}
		int mid=(tree[p].L+tree[p].R)>>1;//二分建树 
		if(R<=mid)Build(L,R,p<<1);//都在mid的左边 
		else if(L>mid)Build(L,R,p<<1|1);//都在mid的右边 
		else Build(L,mid,p<<1),Build(mid+1,R,p<<1|1);//既在mid左边,又在mid右边 
		Up(p);//从子树收集状态
	}
	void Add(int L,int R,int d,int p){
		if(tree[p].L==L&&tree[p].R==R){//两个边界相同则直接返回 
			tree[p].sum+=(R-L+1)*d;
			tree[p].add+=d;
			return;
		}
		Down(p);//将附加值向下传递 
		int mid=(tree[p].L+tree[p].R)>>1;
		if(R<=mid)Add(L,R,d,p<<1);
		else if(L>mid)Add(L,R,d,p<<1|1);
		else {
			Add(L,mid,d,p<<1);
			Add(mid+1,R,d,p<<1|1);
		}
		Up(p); 
	}
	long long Query(int L,int R,int p){
		if(tree[p].L==L&&tree[p].R==R){
			return tree[p].sum;
		}
		Down(p);
		int mid=(tree[p].L+tree[p].R)>>1;
		if(R<=mid)return Query(L,R,p<<1);
		else if(L>mid)return Query(L,R,p<<1|1);
		else return Query(L,mid,p<<1)+Query(mid+1,R,p<<1|1);
	}
}S;
int main(){
	int n,m;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%d",&S.A[i]);
	S.Build(1,n,1);//建树函数 
	while(m--){
		int a,x,y,k;
		scanf("%d",&a);
		if(a==1){
			scanf("%d%d%d",&x,&y,&k);
			S.Add(x,y,k,1);
		}else {
			scanf("%d%d",&x,&y);
			printf("%lld\n",S.Query(x,y,1));
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_35320178/article/details/81088844