线段树维护---区间的平方值和

/*
https://ac.nowcoder.com/acm/contest/917/J
线段树维护区间的每个平方和
 
*/

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+100;
LL tree1[N<<2],tree2[N<<2],lazy[N<<2];
void push_up(int k)
{
	tree1[k]=tree1[k<<1]+tree1[k<<1|1];
	tree2[k]=tree2[k<<1]+tree2[k<<1|1];
}
void build(int l,int r,int k)
{
	lazy[k]=0;
	if(l==r){
		scanf("%lld",&tree1[k]);
		tree2[k]=tree1[k]*tree1[k];
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,k<<1);
	build(mid+1,r,k<<1|1);
	push_up(k);
}
void push_down(int k,int len)
{
	if(lazy[k]){
		tree2[k<<1]+=(len-(len>>1))*lazy[k]*lazy[k]+2*tree1[k<<1]*lazy[k];
		tree2[k<<1|1]+=(len>>1)*lazy[k]*lazy[k]+2*lazy[k]*tree1[k<<1|1];
		
		tree1[k<<1]+=(len-(len>>1))*lazy[k];
		tree1[k<<1|1]+=(len>>1)*lazy[k];
		
		lazy[k<<1]+=lazy[k];
		lazy[k<<1|1]+=lazy[k];
		lazy[k]=0;
	}
}
void update(int x,int y,LL z,int l,int r,int k)
{
	if(x<=l&&y>=r){
		lazy[k]+=z;
		tree2[k]+=(r-l+1)*(z*z)+(2*z*tree1[k]);//注意这里  
		tree1[k]+=(r-l+1)*z;
		return;
	}
	push_down(k,r-l+1);
	int mid=(l+r)>>1;
	if(x<=mid) update(x,y,z,l,mid,k<<1);
	if(y>mid) update(x,y,z,mid+1,r,k<<1|1);
	push_up(k);
}

LL query(int x,int y,int id,int l,int r,int k)
{
	if(x<=l&&y>=r){
		if(id==1) return tree1[k];
		else return tree2[k];
	}
	push_down(k,r-l+1);
	int mid=(l+r)>>1;
	LL sum=0;
	if(x<=mid) sum+=query(x,y,id,l,mid,k<<1);
	if(y>mid) sum+=query(x,y,id,mid+1,r,k<<1|1);
	return sum;
}
int main()
{
	int n,q;
	scanf("%d %d",&n,&q);
	build(1,n,1);
	
	while(q--){
		int id,l,r;
		scanf("%d %d %d",&id,&l,&r);
		if(id==1){
			LL x;
			scanf("%lld",&x);
			update(l,r,x,1,n,1);
		}
		else{
			LL a=query(l,r,1,1,n,1);
			LL b=query(l,r,2,1,n,1);
			printf("%lld\n",(a*a-b)/2);
			
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/CC_1012/article/details/92994175