[BJOI2018]链上二次求和

Problem

luogu传送门 loj传送门
题意感觉已经说的很清楚了,就没有简要题意了。

Solution

定位:线段树维护二次函数

一眼数据结构题(虽然一开始被链吓到了,以为是什么计数问题)。在数据结构上,做区间修改,相信大家都会。关键是如何去计算题目要求的答案。

读完题后,可将答案写成下列式子:

i=lrj=ink=ji+1jai

sx=i=1xai,ssx=i=1xsi,则

=i=lrj=insjsji=i=lr[(j=insj)(j=insji)]=i=lrssnssi1ssni

对于上述式子,在知道ssx已经可以O(n)直接求出,用线段树维护,则可以做到单次询问O(logn)

现在,对于一次[l,r]的区间加,我们需要知道对于ss的影响。

可以直接考虑:

ai (i[l,r])+=d
si (i[l,r])+=d×(il+1)
ssi (i[l,r])+=d×(il+1)×(il+2)2
对于(i>r)的部分,si的贡献相同
所以ssi (i(r,n])+=d×(rl+1)×(rl+2)2+(rl+1)×(ir)×d

将式子展开,再整理,可以得到:

ssi(i[l,r])+=d×i2+(32×L)×i+(L23×L+2)2ssi(i(r,n])+=d×((rl+1)(rl+2)2(r2l×r+r)+(i×ri×l+i))=d×(rl+1)(rl+2)2r×(rl+1)+i×(rl+1))=d×(rl+22r)×(rl+1)+d×(rl+1)×i

对于以上两个式子,我们可以去用线段树分别维护i2,i1,i0的系数。

code:

#include<bits/stdc++.h>

using namespace std;

namespace Reader{
	const int BUF_SIZE=1048576;
	char rr[BUF_SIZE],*csy1,*csy2;
	#define GC (csy1==csy2&&(csy2=(csy1=rr)+fread(rr,1,BUF_SIZE,stdin),csy1==csy2)?EOF:*csy1++)
	template <class T>
	inline void RI(T &t){
		int u=0;char c=GC;
		for(t=0;c<48 || c>57;c=GC){
			if(c==EOF) return;
			u=c=='-'?1:0;
		}
		for(;c>47 && c<58;c=GC) t=(t<<1)+(t<<3)+c-48;
		t=u?-t:t;
	}
	inline void RC(char &c,int Rangemin=0,int Rangemax=127){
		for(c=GC;c<Rangemin || c>Rangemax;c=GC);
	}
	inline void RS(char *a){
		char c=GC;
		for(*a=0;c<33;c=GC)
			if(c==EOF)
                return;
		
		for(;c>32;c=GC) *a++=c;
		*a=0;
	}
	char pbuf[BUF_SIZE],*csy=pbuf;
	inline void WC(const char c){
		if(csy-pbuf==BUF_SIZE) fwrite(pbuf,1,BUF_SIZE,stdout),csy=pbuf;
		*csy++=c;
	}
	template <class T>
	inline void WI(T x){
		static int sta[38];
		int top=0;
		if(x<0) {
			WC('-');
			do{
                sta[top++]=-(x%10);
                x/=10;
            }while(x);
		}
        else
			do{
                sta[top++]=x%10;
                x/=10;
            }while (x);
		while(top) WC(sta[--top]+'0');
//		WC('\n');
	}
	inline void flush(){
		fwrite(pbuf,1,csy-pbuf,stdout);
		csy=pbuf;
	}
} 

typedef long long ll;

#define int long long

const int MAX_N = 200000 + 5;
const ll mod = 1000000000 + 7;
const ll inv2 = 500000000 + 4;
const ll inv6 = 166666668;

int n,m;
ll a[MAX_N],s[MAX_N],ss[MAX_N];

#define ls ((p)<<1)
#define rs ((p)<<1|1)

ll t[MAX_N<<2],i0[MAX_N<<2],i1[MAX_N<<2],i2[MAX_N<<2];


void build(int p,int l,int r){
	if(l==r){
		t[p]=ss[l];
		return;
	}
	int mid=l+r>>1;
	build(ls,l,mid);
	build(rs,mid+1,r);
//	t[p]=(t[ls]+t[rs])%mod;
	t[p]=t[ls]+t[rs];
	if(t[p]>mod) t[p]-=mod;
}

//inline ll s0(ll x){return x>0?x:0;}
inline ll s1(ll x){return x*(x+1)%mod*inv2%mod;}
inline ll s2(ll x){return x*(x+1)%mod*(2*x+1)%mod*inv6%mod;}

inline void calc(int p,int l,int r,ll a,ll b,ll c){
	i2[p]=(i2[p]+a)%mod,i1[p]=(i1[p]+b)%mod,i0[p]=(i0[p]+c)%mod;
	t[p]=(t[p]+(s2(r)-s2(l-1))*a%mod+(s1(r)-s1(l-1))*b%mod+(r-l+1)*c%mod)%mod;
}

inline void pushdown(int p,int l,int r){
	int mid=l+r>>1;
	if(i0[p] || i1[p] || i2[p]){
		calc(ls,l,mid,i2[p],i1[p],i0[p]);
		calc(rs,mid+1,r,i2[p],i1[p],i0[p]);
		i0[p]=i1[p]=i2[p]=0;
	}
}

void modify(int p,int l,int r,int L,int R,ll a,ll b,ll c){
	if(L<=l && r<=R){
		calc(p,l,r,a,b,c);
		return;
	}	   
	pushdown(p,l,r);
	int mid=l+r>>1;
	if(L<=mid) modify(ls,l,mid,L,R,a,b,c);
	if(mid<R) modify(rs,mid+1,r,L,R,a,b,c);
//	t[p]=(t[ls]+t[rs])%mod;
	t[p]=(t[ls]+t[rs]);
	if(t[p]>mod) t[p]-=mod;
}

inline void update(int l,int r,ll d){
	ll len=r-l+1;
	modify(1,0,n,l,r,inv2*d%mod,(3-2*l)*inv2%mod*d%mod,(l*l-3*l+2)%mod*inv2%mod*d%mod);
	if(r<n) modify(1,0,n,r+1,n,0,len*d%mod,((len+1)*inv2%mod-r)*len%mod*d%mod);
}

ll query(int p,int l,int r,int L,int R){
	if(L<=l && r<=R){
		return t[p];
	}
	pushdown(p,l,r);
	int mid=l+r>>1;
	if(L<=mid && mid<R) return (query(ls,l,mid,L,R)+query(rs,mid+1,r,L,R))%mod;
	else if(L<=mid) return query(ls,l,mid,L,R);
	else return query(rs,mid+1,r,L,R);
}

inline ll query(int l,int r){	return (((r-l+1)*query(1,0,n,n,n)%mod-query(1,0,n,l-1,r-1)-query(1,0,n,n-r,n-l))%mod+mod)%mod;
}

signed main(){
	Reader::RI(n);
	Reader::RI(m);
	for(int i=1;i<=n;++i){
		Reader::RI(a[i]);
//		s[i]=(s[i-1]+a[i])%mod;
		s[i]=(s[i-1]+a[i]);
		if(s[i]>mod) s[i]-=mod;
	}
	for(int i=1;i<=n;++i){
		ss[i]=(ss[i-1]+s[i]);
		if(ss[i]>mod) ss[i]-=mod;
//		ss[i]=(ss[i-1]+s[i])%mod;
	}
	build(1,0,n);
	while(m--){
		int op,l,r;
		ll d;
		Reader::RI(op);Reader::RI(l);Reader::RI(r);
		if(l>r) swap(l,r);
		if(op==1){
			Reader::RI(d);
			update(l,r,d);
		}
		else{
			Reader::WI(query(l,r));
			Reader::WC('\n');
		}
	}
	Reader::flush();
	return 0;
}
posted @   Thermalrays  阅读(64)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示