[BJOI2018]链上二次求和

Problem

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

Solution

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

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

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

\[\sum_{i=l}^{r} \sum_{j=i}^n \sum_{k=j-i+1}^{j} a_i \]

\(s_x = \sum_{i=1}^x a_i, ss_x = \sum_{i=1}^x s_i\),则

\[原式 = \sum_{i=l}^{r} \sum_{j=i}^n s_j-s_{j-i} \\ = \sum_{i=l}^{r} [(\sum_{j=i}^n s_j)-(\sum_{j=i}^n s_{j-i})] \\ = \sum_{i=l}^{r} ss_n - ss_{i-1} - ss_{n-i}\]

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

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

可以直接考虑:

\(a_i\) \((i \in [l,r]) += d\)
\(s_i\) \((i \in [l,r]) += d\times(i-l+1)\)
\(ss_i\) \((i \in [l,r]) += d\times\frac{(i-l+1)\times(i-l+2)}{2}\)
对于\((i > r)\)的部分,\(s_i\)的贡献相同
所以\(ss_i\) \((i \in (r,n]) += d \times \frac{(r-l+1)\times(r-l+2)}{2} + (r-l+1) \times (i-r) \times d\)

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

\[ss_i (i \in [l,r]) += d \times \frac{i^2+(3-2 \times L) \times i + (L^2-3 \times L + 2)}{2} \\ ss_i (i \in (r,n]) += d \times (\frac{(r-l+1)(r-l+2)}{2}-(r^2-l\times r + r) + (i \times r - i \times l + i)) \\ = d \times (\frac{r-l+1)(r-l+2)}{2}-r \times(r-l+1) + i \times (r - l + 1)) \\ = d \times (\frac{r-l+2}{2} - r) \times (r-l+1) + d \times (r-l+1) \times i \]

对于以上两个式子,我们可以去用线段树分别维护\(i^2,i^1,i^0\)的系数。

\(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 @ 2022-03-21 20:10  Thermalrays  阅读(58)  评论(0编辑  收藏  举报