[LOJ2512]链上二次求和

先对询问推式子,设$S_i=\sum\limits_{j=1}^ia_j,SS_i=\sum\limits_{j=1}^iS_j$,那么答案是

$\sum\limits_{i=l}^r\sum\limits_{j=i}^nS_j-S_{j-i}=\sum\limits_{i=l}^rSS_n-SS_{i-1}-SS_{n-i}=(r-l+1)SS_n-\sum\limits_{i=l-1}^{r-1}SS_i-\sum\limits_{n-r}^{n-l}SS_i$

所以我们需要维护$SS$的和,直接上线段树,考虑修改$(l,r,v)$对$SS$的影响,令$S_2(n)=\dfrac{n(n+1)}2,len=r-l+1$

对$i\in[l,r]$,$SS_i$会增加$v\cdot S_2(i-l+1)$

对$i\in[r+1,n]$,$SS_i$会增加$v\cdot S_2(len)+v\cdot (i-r)len$

第一种对每个位置的增加量是关于下标下标的二次函数,第二种是一次函数,所以直接维护即可

这个题目本身没啥问题,但是这个坑啊,excited!

题目说“一条链”,修改实际上是区间修改,但实际上修改时会出现$u\gt v$的情况,写正解不swap会挂成$25$分,这个出题人他很棒棒啊?个人认为这种读题坑在省选里坑$75$分有点过分了

#include<stdio.h>
void swap(int&a,int&b){a^=b^=a^=b;}
typedef long long ll;
const ll mod=1000000007,inv2=500000004,inv6=166666668;
ll a[800010],b[800010],c[800010],s[800010],ss[200010];
ll s1(ll n){return n>0?n*(n+1)%mod*inv2%mod:0;}
ll s2(ll n){return n>0?n*(n+1)%mod*(2*n+1)%mod*inv6%mod:0;}
void pushup(int x){s[x]=(s[x<<1]+s[x<<1|1])%mod;}
void ad(int x,ll l,ll r,ll da,ll db,ll dc){
	(a[x]+=da)%=mod;
	(b[x]+=db)%=mod;
	(c[x]+=dc)%=mod;
	(s[x]+=(s2(r)-s2(l-1))*da%mod+(s1(r)-s1(l-1))*db%mod+(r-l+1)*dc%mod)%=mod;
}
void pushdown(int x,int l,int mid,int r){
	if(a[x]|b[x]|c[x]){
		ad(x<<1,l,mid,a[x],b[x],c[x]);
		ad(x<<1|1,mid+1,r,a[x],b[x],c[x]);
		a[x]=b[x]=c[x]=0;
	}
}
void build(int l,int r,int x){
	if(l==r){
		s[x]=ss[l];
		return;
	}
	int mid=(l+r)>>1;
	build(l,mid,x<<1);
	build(mid+1,r,x<<1|1);
	pushup(x);
}
void modify(int L,int R,ll a,ll b,ll c,int l,int r,int x){
	if(L<=l&&r<=R)return ad(x,l,r,a,b,c);
	int mid=(l+r)>>1;
	pushdown(x,l,mid,r);
	if(L<=mid)modify(L,R,a,b,c,l,mid,x<<1);
	if(mid<R)modify(L,R,a,b,c,mid+1,r,x<<1|1);
	pushup(x);
}
ll query(int L,int R,int l,int r,int x){
	if(L<=l&&r<=R)return s[x];
	int mid=(l+r)>>1;
	ll ans=0;
	pushdown(x,l,mid,r);
	if(L<=mid)(ans+=query(L,R,l,mid,x<<1))%=mod;
	if(mid<R)(ans+=query(L,R,mid+1,r,x<<1|1))%=mod;
	return ans;
}
int n;
void modify(ll l,ll r,ll v){
	ll len=r-l+1;
	modify(l,r,inv2*v%mod,(3-2*l)*inv2%mod*v%mod,(l*l-3*l+2)%mod*inv2%mod*v%mod,0,n,1);
	if(r<n)modify(r+1,n,0,len*v%mod,((len+1)*inv2%mod-r)*len%mod*v%mod,0,n,1);
}
int query(ll l,ll r){
	return(((r-l+1)*query(n,n,0,n,1)%mod-query(l-1,r-1,0,n,1)-query(n-r,n-l,0,n,1))%mod+mod)%mod;
}
int main(){
	int m,i,op,x,y,z;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++){
		scanf("%lld",ss+i);
		(ss[i]+=ss[i-1])%=mod;
	}
	for(i=1;i<=n;i++)(ss[i]+=ss[i-1])%=mod;
	build(0,n,1);
	while(m--){
		scanf("%d%d%d",&op,&x,&y);
		if(op==1){
			scanf("%d",&z);
			if(x>y)swap(x,y);
			modify(x,y,z);
		}else
			printf("%d\n",query(x,y));
	}
}

猜你喜欢

转载自www.cnblogs.com/jefflyy/p/9097301.html
今日推荐