P4458 [BJOI2018]链上二次求和
显然线段树,修改操作就是白给,难点在于查询。
对于每一次查询:
其中 \(w_i\) 表示点 \(i\) 的点权。
接下来我们开始 乱搞 这个式子(bushi
设 \(s_n = \sum\limits_{i = 1}^n w_i, ss_n = \sum\limits_{i = 1}^n s_i, sss_n = \sum\limits_{i = 1}^n ss_i\),即 \(s\) 是 \(w\) 的前缀和,\(ss\) 是 \(w\) 的二次前缀和(前缀和的前缀和),\(sss\) 是 \(w\) 的三次前缀和。
然后,我们考虑该如何用线段树来维护 \(s, ss, sss\)。\(s\) 维护起来很简单,难点就在 \(ss\) 和 \(sss\) 上,我们将其继续分解。
考虑每个 \(w_j\) 出现的次数,易知为 \(n - j + 1\),故原式可写成:
令 \(s1_n = \sum\limits_{i = 1}^n (w_i \times i)\),则有:
再来考虑 \(sss_n\):
关于这里为什么没有用 \(ss_n\) 最终的 \(ss_n = (n + 1)s_n - s1_n\) 来进行推导:
因为上式已经经过种种变形以适应线段树的维护,已经不适合再用来推导了,如果用它来推导 \(sss\) 的式子,难免会给自己增添思维上的难度(甚至推不出来)。
还是考虑每个 \(w_j\) 出现的次数:对于 \(k \le j \le i\),\(w_k\) 会被计算 \(1\) 次。
那么 \(w_k\) 出现的次数 \(t_k\) 就可以写成:
所以:
其中 \(s2_n = \sum\limits_{i = 1}^n (w_i \times i^2)\)。
现在,我们就可以通过维护 \(s, s1, s2\) 来维护 \(ss, sss\)。
对于叶子结点:
\(pushup\) 时:
\(pushdown\) 时(以左子举例,右子同理):
记得取模,以及 \(sii\) 可能会爆 \(int\),要开 \(long~long\)。
\(Code\)
#include <bits/stdc++.h>
#define MAXN 200100
#define MOD 1000000007
#define lson pos << 1
#define rson pos << 1 | 1
using namespace std;
typedef long long ll;
const int INV2 = 5e8 + 4;
int n, m;
ll w[MAXN];
struct Seg {
ll s[3], si, sii, lazy;
} t[MAXN << 2];
template<typename _T>
inline void read(_T &_x) {
_x = 0;
_T _f = 1;
char _ch = getchar();
while (_ch < '0' || '9' < _ch) {
if (_ch == '-') _f = -1;
_ch = getchar();
}
while ('0' <= _ch && _ch <= '9') {
_x = (_x << 3) + (_x << 1) + (_ch & 15);
_ch = getchar();
}
_x *= _f;
}
template<typename _T>
inline void write(_T _x) {
if (_x < 0) {
putchar('-');
_x = -_x;
}
if (_x > 9) write(_x / 10);
putchar('0' + _x % 10);
}
void pushup(int pos) {
t[pos].s[0] = (t[lson].s[0] + t[rson].s[0]) % MOD;
t[pos].s[1] = (t[lson].s[1] + t[rson].s[1]) % MOD;
t[pos].s[2] = (t[lson].s[2] + t[rson].s[2]) % MOD;
}
void pushdown(int pos, ll len) {
if (!t[pos].lazy) return;
t[lson].lazy = (t[lson].lazy + t[pos].lazy) % MOD;
t[rson].lazy = (t[rson].lazy + t[pos].lazy) % MOD;
t[lson].s[0] = (t[lson].s[0] + (len - (len >> 1)) * t[pos].lazy) % MOD;
t[lson].s[1] = (t[lson].s[1] + t[pos].lazy * t[lson].si) % MOD;
t[lson].s[2] = (t[lson].s[2] + t[pos].lazy * t[lson].sii) % MOD;
t[rson].s[0] = (t[rson].s[0] + (len >> 1) * t[pos].lazy) % MOD;
t[rson].s[1] = (t[rson].s[1] + t[pos].lazy * t[rson].si) % MOD;
t[rson].s[2] = (t[rson].s[2] + t[pos].lazy * t[rson].sii) % MOD;
t[pos].lazy = 0;
}
void build(int pos, int l, int r) {
if (l == r) {
t[pos].si = l;
t[pos].sii = 1ll * l * l % MOD;
t[pos].s[0] = w[l];
t[pos].s[1] = w[l] * t[pos].si % MOD;
t[pos].s[2] = w[l] * t[pos].sii % MOD;
return;
}
int mid = (l + r) >> 1;
build(lson, l, mid), build(rson, mid + 1, r);
pushup(pos);
t[pos].si = (t[lson].si + t[rson].si) % MOD;
t[pos].sii = (t[lson].sii + t[rson].sii) % MOD;
}
void update(int pos, int l, int r, int x, int y, ll c) {
if (x <= l && r <= y) {
t[pos].lazy = (t[pos].lazy + c) % MOD;
t[pos].s[0] = (t[pos].s[0] + c * (r - l + 1)) % MOD;
t[pos].s[1] = (t[pos].s[1] + t[pos].si * c) % MOD;
t[pos].s[2] = (t[pos].s[2] + t[pos].sii * c) % MOD;
return;
}
pushdown(pos, r - l + 1);
int mid = (l + r) >> 1;
if (x <= mid) update(lson, l, mid, x, y, c);
if (y > mid) update(rson, mid + 1, r, x, y, c);
pushup(pos);
}
ll query(int pos, int l, int r, int x, int y, int id) {
if (x <= l && r <= y) return t[pos].s[id];
pushdown(pos, r - l + 1);
ll res = 0;
int mid = (l + r) >> 1;
if (x <= mid) res = (res + query(lson, l, mid, x, y, id)) % MOD;
if (y > mid) res = (res + query(rson, mid + 1, r, x, y, id)) % MOD;
return res;
}
ll getss() {
return ((n + 1) * query(1, 1, n, 1, n, 0) % MOD - query(1, 1, n, 1, n, 1) + MOD) % MOD;
}
ll getsss(ll x) {
if (x <= 0) return 0;
ll tmp = (query(1, 1, n, 1, x, 2) - ((x << 1) + 3) * query(1, 1, n, 1, x, 1) % MOD + query(1, 1, n, 1, x, 0) * (x + 2) % MOD * (x + 1) % MOD) % MOD;
return tmp * INV2 % MOD;
}
int main() {
read(n), read(m);
for (int i = 1; i <= n; i++) read(w[i]);
build(1, 1, n);
while (m--) {
int op, x, y;
ll c;
read(op), read(x), read(y);
if (x > y) swap(x, y);
if (op == 1) {
read(c);
update(1, 1, n, x, y, c);
} else {
ll tmp = ((y - x + 1) * getss() - (getsss(y - 1) - getsss(x - 2)) - (getsss(n - x) - getsss(n - y - 1))) % MOD;
write((tmp + MOD) % MOD);
putchar('\n');
}
}
return 0;
}
作者:chy12321
出处:https://www.cnblogs.com/chy12321/p/16729909.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现