[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;
}