链上二次求和

link

正在肝的一道黑题……

首先处理那个奇怪的询问操作。我们可以对于那个奇怪的东西进行暴力推式:

ans(l,r)=len=lri=1mlen+1j=ii+len1aj

用前缀和搞一下就是

len=lri=1mlen+1sumi+len1sumi1

分离一下

len=lr(i=lenmsumii=0mlensumi)

emmmm,发现它似乎仍然具有前缀和的性质,考虑搞个前缀和的前缀和(su):

len=lrsumsulen1sumlen

展开:

sum×(rl+1)i=l1r1suii=mrmlsui

于是那个奇怪的询问就变成了单纯的对于su数组的区间和查询。

按照思考此类问题的惯常方法,考虑假如我们给[l,r]中的数都加了一个a,会发生些什么?

Δsumi={0i[1,l1]d×(il+1)i[l,r]d×(rl+1)i[r+1,m]

同样可以得出,假如s(i)=i×(i+1)/2

Δsui={0i[1,l1]d×s(il+1)i[l,r]d×s(rl+1)+d×(rl+1)×(ir)i[r+1,m]

开心地发现i[1,l1]部分不用管,所以对于剩下的两个部分进行处理。首先是i[r+1,M]部分,令len=rl+1

Δsui=d×s(len)+d×len×(ir)=d×s(len)d×len×r+d×len×r

发现前半部分是个定值,相当于是普通区间加;后半部分相当于是区间加 d×len 倍的下标。如何实现后面再说。再看一下对于 i[r+1,m] 部分怎么处理。

2Δsuid=(il+1)2+(il+1)=i2+(l1)2+2i(1l)+i+(1l)=i2+(32l)i+(l1)(l2)

所以

2Δsui=di2+(3d2ld)i+(l1)(l2)d

发现(l1)(l2)是固定的,相当于是区间加。于是我们就需要一种数据结构可以完成区间加下标平方和区间加下标。这应该是可以做到的。区间加下标好办,那区间加下标平方曾么搞?有平方和公式啊。

i=1mi2=m(m+1)(2m+1)6

最后我们发现,上面推出来的柿子为真正增量的两倍。取模意义下除法灰常麻烦,于是我的做法是线段树中维护的是增量的两倍,询问时乘上2的逆元就可以了。

最后说明一点,由于这道题对取模的要求苛刻得有些丧心病狂,一定要认真取模。然后本蒟蒻代码能力极差,码风自然氢气,见谅。

#include<cstdio>
//#define zczc
#define int long long
const int N=200010;
const int yy=500000004;
const int mod=1000000007;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar();}
    wh*=f;return;
}

int m,n,a[N];

#define lc (wh<<1)
#define rc (wh<<1|1)
#define mid (t[wh].l+t[wh].r>>1)
//直接区间加的那棵树
namespace ta{
	struct node{
		int l,r,data,lazy;
	}t[N<<2];
	inline void pushup(int wh){
		t[wh].data=(t[lc].data+t[rc].data)%mod;
		return;
	}
	inline void pushnow(int wh,int val){
		t[wh].lazy+=val;
		t[wh].lazy%=mod;
		t[wh].data+=val*(t[wh].r-t[wh].l+1)%mod;
		t[wh].data%=mod;
		return;
	}
	inline void pushdown(int wh){
		if(t[wh].lazy){
			pushnow(lc,t[wh].lazy);
			pushnow(rc,t[wh].lazy);
			t[wh].lazy=0;
		}
		return;
	}
	inline void build(int wh,int l,int r){
		t[wh].l=l,t[wh].r=r;
		if(l==r){
			t[wh].data=a[l];
			return;
		}
		build(lc,l,mid);
		build(rc,mid+1,r);
		pushup(wh);
		return;
	}
	inline void change(int wh,int wl,int wr,int val){
		if(wl<=t[wh].l&&t[wh].r<=wr){
			pushnow(wh,val);
			return;
		}
		pushdown(wh);
		if(wl<=mid)change(lc,wl,wr,val);
		if(wr>mid)change(rc,wl,wr,val);
		pushup(wh);
		return; 
	}
	inline int work(int wh,int wl,int wr){
		if(wl<=t[wh].l&&t[wh].r<=wr){
			return t[wh].data;
		}
		pushdown(wh);
		int an=0;
		if(wl<=mid)an+=work(lc,wl,wr);
		if(wr>mid)an+=work(rc,wl,wr);
		return an%mod; 
	}
	inline int ask(int wh,int pl){
		if(t[wh].l==t[wh].r)return t[wh].data;
		pushdown(wh);
		if(pl<=mid)return ask(lc,pl);
		else return ask(rc,pl);
	}
}
//区间加下标的那棵树 
namespace tb{
	struct node{
		int l,r,data,lazy;
	}t[N<<2];
	inline void pushup(int wh){
		t[wh].data=(t[lc].data+t[rc].data)%mod;
		return;
	}
	inline int s(int l,int r){
		return (l+r)*(r-l+1)/2%mod;
	}
	inline void pushnow(int wh,int val){
		t[wh].lazy+=val;t[wh].lazy%=mod;
		t[wh].data+=val*s(t[wh].l,t[wh].r)%mod;
		t[wh].data%=mod;
		return;
	}
	inline void pushdown(int wh){
		if(t[wh].lazy){
			pushnow(lc,t[wh].lazy);
			pushnow(rc,t[wh].lazy);
			t[wh].lazy=0;
		}
		return;
	}
	inline void build(int wh,int l,int r){
		t[wh].l=l,t[wh].r=r;
		if(l==r)return;
		build(lc,l,mid);
		build(rc,mid+1,r);
		pushup(wh);
		return;
	}
	inline void change(int wh,int wl,int wr,int val){
		if(wl<=t[wh].l&&t[wh].r<=wr){
			pushnow(wh,val);
			return;
		}
		pushdown(wh);
		if(wl<=mid)change(lc,wl,wr,val);
		if(wr>mid)change(rc,wl,wr,val);
		pushup(wh);
		return; 
	}
	inline int work(int wh,int wl,int wr){
		if(wl<=t[wh].l&&t[wh].r<=wr){
			return t[wh].data;
		}
		pushdown(wh);
		int an=0;
		if(wl<=mid)an+=work(lc,wl,wr);
		if(wr>mid)an+=work(rc,wl,wr);
		return an%mod; 
	}
	inline int ask(int wh,int pl){
		if(t[wh].l==t[wh].r)return t[wh].data;
		pushdown(wh);
		if(pl<=mid)return ask(lc,pl);
		else return ask(rc,pl);
	}
}
//区间加下标平方的那棵树
namespace tc{
	struct node{
		int l,r,data,lazy;
	}t[N<<2];
	inline void pushup(int wh){
		t[wh].data=(t[lc].data+t[rc].data)%mod;
		return;
	}
	inline int s(int wh){
		return wh*(wh+1)/2*(2*wh+1)/3%mod;
	}
	inline void pushnow(int wh,int val){
		t[wh].lazy+=val;t[wh].lazy%=mod;
		t[wh].data+=val*(s(t[wh].r)-s(t[wh].l-1)+mod)%mod;
		t[wh].data%=mod;
		return;
	}
	inline void pushdown(int wh){
		if(t[wh].lazy){
			pushnow(lc,t[wh].lazy);
			pushnow(rc,t[wh].lazy);
			t[wh].lazy=0;
		}
		return;
	}
	inline void build(int wh,int l,int r){
		t[wh].l=l,t[wh].r=r;
		if(l==r)return;
		build(lc,l,mid);
		build(rc,mid+1,r);
		pushup(wh);
		return;
	}
	inline void change(int wh,int wl,int wr,int val){
		if(wl<=t[wh].l&&t[wh].r<=wr){
			pushnow(wh,val);
			return;
		}
		pushdown(wh);
		if(wl<=mid)change(lc,wl,wr,val);
		if(wr>mid)change(rc,wl,wr,val);
		pushup(wh);
		return; 
	}
	inline int work(int wh,int wl,int wr){
		if(wl<=t[wh].l&&t[wh].r<=wr){
			return t[wh].data;
		}
		pushdown(wh);
		int an=0;
		if(wl<=mid)an+=work(lc,wl,wr);
		if(wr>mid)an+=work(rc,wl,wr);
		return an%mod; 
	}
	inline int ask(int wh,int pl){
		if(t[wh].l==t[wh].r)return t[wh].data;
		pushdown(wh);
		if(pl<=mid)return ask(lc,pl);
		else return ask(rc,pl);
	}
} 
#undef lc
#undef rc
#undef mid

inline int solve(int l,int r){
	if(l==r){
		return (ta::ask(1,l)+(tb::ask(1,l)+tc::ask(1,l))%mod*yy%mod)%mod;
	}
	else{
		return (ta::work(1,l,r)+(tb::work(1,l,r)+tc::work(1,l,r))%mod*yy%mod)%mod;
	}
}

signed main(){
	
	#ifdef zczc
	freopen("a.in","r",stdin);
	#endif
	
	read(m);read(n);
	for(int i=1;i<=m;i++){read(a[i]);a[i]+=a[i-1];a[i]%=mod;}
	for(int i=1;i<=m;i++)a[i]+=a[i-1],a[i]%=mod;
	//for(int i=1;i<=m;i++)printf("%d ",a[i]);
	ta::build(1,0,m);
	tb::build(1,0,m);
	tc::build(1,0,m);
	int op,l,r,val;
	
	while(n--){
		read(op);read(l);read(r);
		if(l>r){int s1=l;l=r;r=s1;}
		if(op==2){
			int an=solve(m,m)*(r-l+1)-solve(l-1,r-1)-solve(m-r,m-l);
			printf("%lld\n",(an%mod+mod)%mod);
		}
		else{
			read(val);
			if(r<m){
				int len=r-l+1;
				ta::change(1,r+1,m,((val*len%mod*(len+1)%mod*yy%mod-val*len%mod*r%mod)%mod+mod)%mod);
				tb::change(1,r+1,m,2*val*len%mod);
			}
			ta::change(1,l,r,(l-1)*(l-2)%mod*val%mod*yy%mod);
			tb::change(1,l,r,val*(3-2*l)%mod);
			tc::change(1,l,r,val);
		}
	}
	
	return 0;
}
posted @   Feyn618  阅读(51)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示