30分求调
查看原帖
30分求调
547725
Zilljy258楼主2024/1/5 16:26

线段树上求平方和 和 差分。

sm1sm1 : 区间和。

sm2sm2 : 平方和。

lenlen : 所求区间长度的逆元。

atratr : 单点修改。

qry2qry2 : 求 所求区间的 区间和 和 平方和。

S1S1 : 存 所求区间的 区间和。

S2S2 : 存 所求区间的 平方和。

#include<iostream>
#include<cstdio>
#define lo (nw<<1) 
#define ro (nw<<1|1)
#define md (l+r>>1)
#define p 1000000007

using namespace std;

int n,m;
long long a[200010];
long long S1,S2;
struct Tree{
	long long sm1;
	long long sm2;
	int siz;
}t[800010];


long long ksm(long long a){
	int b=p-2;
	long long ans=1;
	while(b){
		if(b&1) ans=(ans*a)%p;
		b>>=1;
		a=(a*a)%p; 
	}
	return ans;
}

void upd(int nw){
	t[nw].siz=t[lo].siz+t[ro].siz;
	t[nw].sm1=(t[lo].sm1+t[ro].sm1)%p;
	t[nw].sm2=(t[lo].sm2+t[ro].sm2)%p;
	return ;
} 

void bld(int nw,int l,int r){
	if(l==r){
		t[nw].sm1=a[l]%p;
		t[nw].sm2=(a[l]*a[l])%p;
		t[nw].siz=1;
		return ;
	}
	bld(lo,l,md);
	bld(ro,md+1,r);
	upd(nw);
	return ;
}

void atr(int nw,int l,int r,int x,long long z){
	if(x==l&&x==r){
		t[nw].sm2=(t[nw].sm2+2*z*t[nw].sm1%p+t[nw].siz*z*z%p)%p;
		t[nw].sm1=(t[nw].sm1+z*t[nw].siz%p)%p; 
		return ;
	}
	if(x<=md) atr(lo,l,md,x,z);
	else
	if(x>md) atr(ro,md+1,r,x,z);
	upd(nw);
	return ;
}

void qry2(int nw,int l,int r,int x,int y){
	if(x<=l&&r<=y){
		S1=(S1+t[nw].sm1)%p;
		S2=(S2+t[nw].sm2)%p;
		return ;
	}
	if(x<=md) qry2(lo,l,md,x,y);
	if(y>md) qry2(ro,md+1,r,x,y);
	return ;
}

signed main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%lld",&a[i]);
		a[i]%=p; 
	}
	bld(1,1,n);
	int op,x,y;
	long long k;
	for(int i=1;i<=m;++i){
		S1=S2=0;
		scanf("%d%d",&op,&x);
		if(op==1){
			scanf("%lld",&k);
			k%=p;
			atr(1,1,n,x,k);
		}
		else if(op==2){
			scanf("%d",&y);
			qry2(1,1,n,x,y);
			int len=ksm(y-x+1)%p;
			printf("%lld\n",((S2*len%p-(S1*len%p)*(S1*len%p))%p+p)%p);
		}
	}
	return 0;
}

好人有好报好人一生108胎,个个上梁山好人一生平安

谢谢!

2024/1/5 16:26
加载中...