# NOI模拟（5.11） BJOID2T2 链上二次求和 （bzoj5291）

5.11 模拟 BJOI2018D2T2

sum2[l, r] += x * (l + r) * len / 2;

sum2[l, r] += d * l * (len + 1) * len / 2;

sum2[l, r] += num[len] * d;

(PS：出题人跟本没打算让你过，中间很多地方的u, v都是反的，并没有告诉你u <= v，直接玩就死定了)

Source:

/*
created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>

static const int IN_LEN = 1024 * 1024;
static char buf[IN_LEN], *s, *t;
if (s == t) {
t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
if (s == t) return -1;
}
return *s++;
}

// /*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = read(), iosig = false; !isdigit(c); c = read()) {
if (c == -1) return ;
if (c == '-') iosig = true;
}
for (x = 0; isdigit(c); c = read())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN];
char *oh = obuf;
inline void write_char(char c) {
if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
*oh++ = c;
}

template<class T>
inline void W(T x) {
static int buf[30], cnt;
if (x == 0) write_char('0');
else {
if (x < 0) write_char('-'), x = -x;
for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
while (cnt) write_char(buf[cnt--]);
}
}

inline void flush() {
fwrite(obuf, 1, oh - obuf, stdout), oh = obuf;
}

/*
template<class T>
inline void R(T &x) {
static char c;
static bool iosig;
for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
if (c == '-') iosig = true;
for (x = 0; isdigit(c); c = getchar())
x = ((x << 2) + x << 1) + (c ^ '0');
if (iosig) x = -x;
}
//*/

// #define int long long
const int MAXN = 200000 + 10;
const int mod = 1000000000 + 7;

int n, m, type, l, r, x;
long long a[MAXN], num[MAXN];

inline void add(long long &x, int t) {
x += t, (x >= mod) ? (x -= mod) : x;
}

inline int fix(int a, int b) {
return (a += b), (a >= mod) ? (a -= mod) : a;
}

struct node {
long long fir, d, sum1, sum2;
} tree[MAXN << 2 | 1];

struct data {
long long sum1, sum2;
data() {}
data(long long sum1, long long sum2) : sum1(sum1), sum2(sum2) {};
inline data operator + (const data &a) const {
return data(sum1 + a.sum1, sum2 + a.sum2);
}
} ;

inline void update(int k) {
tree[k].sum1 = fix(tree[k << 1].sum1, tree[k << 1 | 1].sum1);
tree[k].sum2 = fix(tree[k << 1].sum2, tree[k << 1 | 1].sum2);
}

inline void modify(int k, int l, int r, int fir, int d) {
long long len = r - l + 1, t = len * (len + 1) / 2 % mod;
tree[k].sum1 = (tree[k].sum1 + len * fir + t * d) % mod;
tree[k].sum2 = (tree[k].sum2 + len * (l + r) / 2 % mod * fir
+ t * d % mod * l + num[len] * d) % mod;
}

inline void push_down(int k, int l, int mid, int r) {
if (tree[k].fir == 0 && tree[k].d == 0) return ;
modify(k << 1, l, mid, tree[k].fir, tree[k].d);
modify(k << 1 | 1, mid + 1, r, (tree[k].fir +
tree[k].d * (mid + 1 - l)) % mod, tree[k].d);
tree[k].fir = tree[k].d = 0;
}

inline void build(int k, int l, int r) {
if (l == r) {
tree[k].sum1 = a[l], tree[k].sum2 = (long long)l * a[l] % mod;
return ;
}
int mid = l + r >> 1;
build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r), update(k);
}

inline void modify(int k, int l, int r, int ql, int qr, int fir, int d) {
if (ql == l && r == qr) return modify(k, l, r, fir, d);
int mid = l + r >> 1;
push_down(k, l, mid, r);
if (qr <= mid) modify(k << 1, l, mid, ql, qr, fir, d);
else if (ql > mid) modify(k << 1 | 1, mid + 1, r, ql, qr, fir, d);
else modify(k << 1, l, mid, ql, mid, fir, d),
modify(k << 1 | 1, mid + 1, r, mid + 1, qr,
fix(fir, (long long)(mid + 1 - ql) * d % mod), d);
update(k);
}

inline data query(int k, int l, int r, int ql, int qr) {
if (ql <= l && r <= qr) return data(tree[k].sum1, tree[k].sum2);
int mid = l + r >> 1;
push_down(k, l, mid, r);
if (qr <= mid) return query(k << 1, l, mid, ql, qr);
else if (ql > mid) return query(k << 1 | 1, mid + 1, r, ql, qr);
else return query(k << 1, l, mid, ql, qr)
+ query(k << 1 | 1, mid + 1, r, ql, qr);
}

inline void modify(int l, int r, int d) {
if (l > r) std::swap(l, r);
modify(1, 0, n, l, r, 0, d);
if (r != n) modify(1, 0, n, r + 1, n, (long long)(r - l + 1) * d % mod, 0);
}

inline long long query(int pos) {
data s1 = query(1, 0, n, 0, n - pos), s2 = query(1, 0, n, pos, n);
s1.sum1 %= mod, s1.sum2 %= mod, s2.sum1 %= mod, s2.sum2 %= mod;
long long ans = s2.sum2 - s2.sum1 * (pos - 1) +
s1.sum2 - s1.sum1 * (n - pos + 1);
return ans;
}

inline void query(int l, int r) {
if (l > r) std::swap(l, r);
W(((query(l) - ((r == n) ? 0 : query(r + 1))) % mod + mod) % mod);
write_char('\n');
}

inline void solve() {
R(n), R(m);
for (int i = 1; i <= n; ++i) R(a[i]), add(a[i], a[i - 1]);
for (int i = 1; i <= n; ++i)
num[i] = (num[i - 1] + (long long)i * (i - 1)) % mod;
build(1, 0, n);
while (m--) {
R(type);
if (type == 1) R(l), R(r), R(x), modify(l, r, x);
else R(l), R(r), query(l, r);
}
}

// #undef int
int main() {
//freopen("in.in", "r", stdin);
//freopen("out1.out", "w", stdout);
solve();
flush();
return 0;
}