给定两个长度为 n n n的序列 a , b a,b a,b。
有 q q q次操作,每次操作l r k
表示将序列 b b b中区间 [ l , r ] [l,r] [l,r]上的每个值加上 k k k。
每次操作结束后,查询:
∑ l = 1 n ∑ r = l n ( ∑ i = l r a i ) × ( ∑ i = l r b i ) \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)
输出答案模 1 0 9 + 7 10^9+7 109+7后的值。
1 ≤ n ≤ 5 × 1 0 5 , q ≤ 1 0 6 1\le n\leq 5\times 10^5,q\leq 10^6 1≤n≤5×105,q≤106
1 ≤ l ≤ r ≤ n , − 1 0 9 ≤ a i , b i , k ≤ 1 0 9 1\leq l\leq r\leq n,-10^9\leq a_i,b_i,k\leq 10^9 1≤l≤r≤n,−109≤ai,bi,k≤109
我们先考虑转化题目中的式子。可以发现这个式子就是 [ 1 , n ] [1,n] [1,n]的每个子区间的 a a a值和与 b b b值和的乘积之和,那我们枚举每个 b b b,看有多少个区间包括 b b b,然后求区间的 a a a值和。于是
a n s = ∑ i = 1 n b i × ∑ l = 1 i ∑ r = i n ∑ j = l r a i ans=\sum\limits_{i=1}^nb_i\times \sum\limits_{l=1}^i\sum\limits_{r=i}^n\sum\limits_{j=l}^ra_i ans=i=1∑nbi×l=1∑ir=i∑nj=l∑rai
设 s i s_i si为 a i a_i ai的前缀和,那么
a n s = ∑ i = 1 n b i × ∑ l = 1 i ∑ r = i n s r − s l − 1 ans=\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 = 1 i ∑ r = i n s r − s l − 1 \sum\limits_{l=1}^i\sum\limits_{r=i}^ns_r-s_{l-1} l=1∑ir=i∑nsr−sl−1可以变为 ( i × ∑ r = i n s r ) − ( ( n − i + 1 ) × ∑ l = 1 i s l − 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),这两个部分可以分别用后缀和以及前缀和求出,记 v i = ∑ l = 1 i ∑ r = i n s r − s l − 1 v_i=\sum\limits_{l=1}^i\sum\limits_{r=i}^ns_r-s_{l-1} vi=l=1∑ir=i∑nsr−sl−1,那么一开始时答案为 ∑ i = 1 n b i × v i \sum\limits_{i=1}^nb_i\times v_i i=1∑nbi×vi。
每次将一个区间加上 k k k之后,答案会增加 ∑ i = l r k × v i = k × ∑ i = l r v i \sum\limits_{i=l}^rk\times v_i=k\times \sum\limits_{i=l}^rv_i i=l∑rk×vi=k×i=l∑rvi,我们求 v v v的前缀和 s v sv sv,那么每次修改对答案的贡献就是 k × ( s v r − s v l − 1 ) k\times (sv_r-sv_{l-1}) k×(svr−svl−1),这样我们就可以 O ( 1 ) O(1) O(1)处理每次询问。因为题目只需要求答案,所以我们不需要真的去修改 b i b_i bi。
时间复杂度为 O ( n + q ) O(n+q) O(n+q)。
#include
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;
}