题解
转化一下可以变成所有小于等于r的减去小于等于l - 1的
然后我们求小于等于x的
显然是
(sum_{i = 1}^{n} sum_{j = 1}^{min(i,x)} sum[i] - sum[i - j])
对于([x,N - x])前缀和被加了(x)遍
对于([1,N - x])前缀和被减了(x)遍
对于([1,x - 1])前缀和被加了下标那么多遍
对于([N - x + 1,N])前缀和被减了N - 下标遍
然后要维护什么就很清楚了
(sum_{i = L}^{R} sum[i]) 和(sum_{i = L}^{R} sum[i] * i)
区间加相当于给一段前缀和加上一个等差数列,这段区间之后加上一个常值数列
区间加等差数列维护区间和,第一个很好维护,第二个只要拆拆式子就好了
(sum_{i = 0}^{R - L + 1} (L + i) * (a + i * d))
(sum_{i = 0}^{R - L + 1} (L + i) * a + (L + i) * i * d)
(sum_{i = 0}^{R - L + 1} (L + i) * a + L * i * d + i * i * d)
拆成三段,第一段是一个等差数列乘一个常数
第二段是(L)乘上一个等差数列
第三个可以用公式(frac{k(k + 1)(2 * k + 1)}{6})算然后乘上(d)
啥,你说常数多大?我没细想= =
最慢好像跑了2.5s,时限4s。。。
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define space putchar(' ')
#define enter putchar('
')
#define mp make_pair
#define MAXN 200005
#define pb push_back
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
template<class T>
void read(T &res) {
res = 0;char c = getchar();T f = 1;
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
res = res * 10 + c - '0';
c = getchar();
}
res *= f;
}
template<class T>
void out(T x) {
if(x < 0) {putchar('-');x = -x;}
if(x >= 10) {
out(x / 10);
}
putchar('0' + x % 10);
}
const int MOD = 1000000007;
int inc(int a,int b) {
return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
return 1LL * a * b % MOD;
}
void update(int &x,int y) {
x = inc(x,y);
}
int a[MAXN],N,M;
struct node {
int L,R,a,b,sum[2];
}tr[MAXN * 4];
int f(int x) {
return mul(mul(x,(MOD + 1) / 6),mul(x + 1,(1LL * 2 * x + 1) % MOD));
}
void addlazy(int u,int a,int b) {
int l = tr[u].R - tr[u].L;
update(tr[u].sum[0] , mul( inc( mul( 2 , a ) , mul( b , l ) ) , mul( l + 1 , (MOD + 1) / 2 ) ) );
update(tr[u].sum[1] , mul( a , mul( tr[u].R + tr[u].L , mul( l + 1 , (MOD + 1) / 2 ) ) ) );
update(tr[u].sum[1] , mul( mul( tr[u].L , b ) , mul( mul( l , l + 1 ) , (MOD + 1) / 2 ) ) );
update(tr[u].sum[1] , mul( b , f(l) ) );
update(tr[u].a,a);update(tr[u].b,b);
}
void update(int u) {
for(int i = 0 ; i <= 1 ; ++i) {
tr[u].sum[i] = inc(tr[u << 1].sum[i],tr[u << 1 | 1].sum[i]);
}
}
void push_down(int u) {
if(tr[u].a || tr[u].b) {
int mid = (tr[u].L + tr[u].R) >> 1;
addlazy(u << 1,tr[u].a,tr[u].b);
addlazy(u << 1 | 1,inc(tr[u].a,mul(mid + 1 - tr[u].L,tr[u].b)),tr[u].b);
tr[u].a = tr[u].b = 0;
}
}
void build(int u,int l,int r) {
tr[u].L = l;tr[u].R = r;
if(l == r) {tr[u].sum[0] = a[l];tr[u].sum[1] = mul(a[l],l);return;}
int mid = (l + r) >> 1;
build(u << 1,l,mid);build(u << 1 | 1,mid + 1,r);
update(u);
}
int Query(int u,int l,int r,int id) {
if(tr[u].L == l && tr[u].R == r) return tr[u].sum[id];
int mid = (tr[u].L + tr[u].R) >> 1;
push_down(u);
if(r <= mid) return Query(u << 1,l,r,id);
else if(l > mid) return Query(u << 1 | 1,l,r,id);
else return inc(Query(u << 1,l,mid,id),Query(u << 1 | 1,mid + 1,r,id));
}
void Change(int u,int l,int r,int a,int b) {
if(tr[u].L == l && tr[u].R == r) {addlazy(u,a,b);return;}
push_down(u);
int mid = (tr[u].L + tr[u].R) >> 1;
if(r <= mid) Change(u << 1,l,r,a,b);
else if(l > mid) Change(u << 1 | 1,l,r,a,b);
else {Change(u << 1,l,mid,a,b);Change(u << 1 | 1,mid + 1,r,inc(a,mul(b,mid + 1 - l)),b);}
update(u);
}
void Init() {
read(N);read(M);
for(int i = 1 ; i <= N ; ++i) {
read(a[i]);
update(a[i],a[i - 1]);
}
build(1,1,N);
}
int Calc(int x) {
if(!x) return 0;
int res = 0;
update(res,mul(Query(1,x,N,0),x));
if(N != x) update(res,MOD - mul(Query(1,1,N - x,0),x));
if(x != 1) update(res,Query(1,1,x - 1,1));
update(res,MOD - inc( mul( N , Query(1,N - x + 1,N,0) ) , MOD - Query(1,N - x + 1,N,1) ) );
return res;
}
void Solve() {
int op,l,r,d;
for(int i = 1 ; i <= M ; ++i) {
read(op);read(l);read(r);
if(op == 1) {
read(d);
if(l > r) swap(l,r);
Change(1,l,r,d,d);
if(r < N) Change(1,r + 1,N,mul(d,r - l + 1),0);
}
else {
out(inc(Calc(r),MOD - Calc(l - 1)));enter;
}
}
}
int main() {
#ifdef ivorysi
freopen("f1.in","r",stdin);
#endif
Init();
Solve();
}