题目大意
给定两个长度为nnn的序列a,ba,ba,b。
有qqq次操作,每次操作l r k
表示将序列bbb中区间[l,r][l,r][l,r]上的每个值加上kkk。
每次操作结束后,查询:
∑l=1n∑r=ln(∑i=lrai)×(∑i=lrbi)\sum\limits_{l=1}^n\sum\limits_{r=l}^n(\sum\limits_{i=l}^ra_i)\times (\sum\limits_{i=l}^rb_i)l=1∑nr=l∑n(i=l∑rai)×(i=l∑rbi)
输出答案模109+710^9+7109+7后的值。
1≤n≤5×105,q≤1061\le n\leq 5\times 10^5,q\leq 10^61≤n≤5×105,q≤106
1≤l≤r≤n,−109≤ai,bi,k≤1091\leq l\leq r\leq n,-10^9\leq a_i,b_i,k\leq 10^91≤l≤r≤n,−109≤ai,bi,k≤109
题解
我们先考虑转化题目中的式子。可以发现这个式子就是[1,n][1,n][1,n]的每个子区间的aaa值和与bbb值和的乘积之和,那我们枚举每个bbb,看有多少个区间包括bbb,然后求区间的aaa值和。于是
ans=∑i=1nbi×∑l=1i∑r=in∑j=lraians=\sum\limits_{i=1}^nb_i\times \sum\limits_{l=1}^i\sum\limits_{r=i}^n\sum\limits_{j=l}^ra_ians=i=1∑nbi×l=1∑ir=i∑nj=l∑rai
设sis_isi为aia_iai的前缀和,那么
ans=∑i=1nbi×∑l=1i∑r=insr−sl−1ans=\sum\limits_{i=1}^nb_i\times \sum\limits_{l=1}^i\sum\limits_{r=i}^ns_r-s_{l-1}ans=i=1∑nbi×l=1∑ir=i∑nsr−sl−1
后面的∑l=1i∑r=insr−sl−1\sum\limits_{l=1}^i\sum\limits_{r=i}^ns_r-s_{l-1}l=1∑ir=i∑nsr−sl−1可以变为(i×∑r=insr)−((n−i+1)×∑l=1isl−1)(i\times \sum\limits_{r=i}^ns_r)-((n-i+1)\times \sum\limits_{l=1}^is_{l-1})(i×r=i∑nsr)−((n−i+1)×l=1∑isl−1),这两个部分可以分别用后缀和以及前缀和求出,记vi=∑l=1i∑r=insr−sl−1v_i=\sum\limits_{l=1}^i\sum\limits_{r=i}^ns_r-s_{l-1}vi=l=1∑ir=i∑nsr−sl−1,那么一开始时答案为∑i=1nbi×vi\sum\limits_{i=1}^nb_i\times v_ii=1∑nbi×vi。
每次将一个区间加上kkk之后,答案会增加∑i=lrk×vi=k×∑i=lrvi\sum\limits_{i=l}^rk\times v_i=k\times \sum\limits_{i=l}^rv_ii=l∑rk×vi=k×i=l∑rvi,我们求vvv的前缀和svsvsv,那么每次修改对答案的贡献就是k×(svr−svl−1)k\times (sv_r-sv_{l-1})k×(svr−svl−1),这样我们就可以O(1)O(1)O(1)处理每次询问。因为题目只需要求答案,所以我们不需要真的去修改bib_ibi。
时间复杂度为O(n+q)O(n+q)O(n+q)。
code
#include<bits/stdc++.h>
using namespace std;
const int N=500000;
const long long mod=1e9+7;
int n,q,a[N+5],b[N+5],s[N+5],s1[N+5],s2[N+5];
long long ans=0,v[N+5],sv[N+5];
int main()
{
freopen("meirin.in","r",stdin);
freopen("meirin.out","w",stdout);
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[i]=(a[i]+mod)%mod;
s[i]=(s[i-1]+a[i])%mod;
}
for(int i=1;i<=n;i++){
scanf("%d",&b[i]);
b[i]=(b[i]+mod)%mod;
}
for(int i=n;i>=1;i--){
s1[i]=(s1[i+1]+s[i])%mod;
}
for(int i=1;i<=n;i++){
s2[i]=(s2[i-1]+s[i])%mod;
}
for(int i=1;i<=n;i++){
v[i]=1ll*i*s1[i]-1ll*(n-i+1)*s2[i-1];
v[i]=(v[i]%mod+mod)%mod;
sv[i]=(sv[i-1]+v[i])%mod;
}
for(int i=1;i<=n;i++) ans=(ans+b[i]*v[i])%mod;
while(q--){
int l,r,k;
scanf("%d%d%d",&l,&r,&k);
k=(k+mod)%mod;
ans=(ans+(sv[r]-sv[l-1]+mod)%mod*k%mod)%mod;
printf("%lld\n",ans);
}
return 0;
}