P1438 无聊的数列
P1438 无聊的数列
题目描述
维护一个数列 \(a_i\),支持两种操作:
-
1 l r K D
:给出一个长度等于 \(r-l+1\) 的等差数列,首项为 \(K\),公差为 \(D\),并将它对应加到 \([l,r]\) 范围中的每一个数上。即:令 \(a_l=a_l+K,a_{l+1}=a_{l+1}+K+D\ldots a_r=a_r+K+(r-l) \times D\)。 -
2 p
:询问序列的第 \(p\) 个数的值 \(a_p\)。
输入格式
第一行两个整数数 \(n,m\) 表示数列长度和操作个数。
第二行 \(n\) 个整数,第 \(i\) 个数表示 \(a_i\)。
接下来的 \(m\) 行,每行先输入一个整数 \(opt\)。
若 \(opt=1\) 则再输入四个整数 \(l\ r\ K\ D\);
若 \(opt=2\) 则再输入一个整数 \(p\)。
输出格式
对于每个询问,一行一个整数表示答案。
样例 #1
样例输入 #1
5 2
1 2 3 4 5
1 2 4 1 2
2 3
样例输出 #1
6
提示
数据规模与约定
对于 \(100\%\) 数据,\(0\le n,m \le 10^5,-200\le a_i,K,D\le 200, 1 \leq l \leq r \leq n, 1 \leq p \leq n\)。
入手
在某个区间里对应加上一个等差数列。
查询第 \(p\) 个数的值。
假如一个序列是
0 0 0 0 0 0
在2-5
这个区间里加入首项为 2,公差为 5 的等差数列,数列变为
0 2 7 12 17 0
差分一下这个数组
0 2 5 5 5 -17
发现了吗?
我们在这个差分序列中的2处加入的首项,3-5处加入了相同的公差,6处加入了-(2+3*5)
所以我们维护一个差分序列的线段树,就在差分线段树上进行查询,每次要查询序列的第q个数,那么我们在线段树上的操作就是查询第 [1,q] 区间的和,我们要维护一个sum,和懒标记tag
代码如下:
#include <bits/stdc++.h>
using i64 = long long;
constexpr int N = 100010;
struct node {
int l, r;
i64 sum, tag;
} tr[N << 2];
int n, m;
int a[N], b[N];
void pushup(int u) {
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void pushdown(int u) {
int mid = (tr[u].l + tr[u].r) >> 1;
if (tr[u].tag) {
tr[u << 1].tag += tr[u].tag;
tr[u << 1].sum += tr[u].tag * (mid - tr[u].l + 1);
tr[u << 1 | 1].tag += tr[u].tag;
tr[u << 1 | 1].sum += tr[u].tag * (tr[u].r - mid);
tr[u].tag = 0;
}
}
void build(int u, int l, int r) {
if (l == r) {
tr[u] = {l, r, b[l], 0};
return;
}
tr[u] = {l, r};
int mid = l + r >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void modify(int u, int l, int r, int x) {
if (l <= tr[u].l && r >= tr[u].r) {
tr[u].sum += (tr[u].r - tr[u].l + 1) * x;
tr[u].tag += x;
return;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if (l <= mid) modify(u << 1, l, r, x);
if (r > mid) modify(u << 1 | 1, l, r, x);
pushup(u);
}
i64 query(int u, int l, int r) {
if (l <= tr[u].l && r >= tr[u].r) {
return tr[u].sum;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
i64 res = 0;
if (l <= mid) res += query(u << 1, l, r);
if (r > mid) res += query(u << 1 | 1, l, r);
pushup(u);
return res;
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cin >> n >> m;
for (int i = 1; i <= n; i++ ) {
std::cin >> a[i];
b[i] = a[i] - a[i - 1];
}
build(1, 1, n);
while (m --) {
int op, l, r, k, d;
std::cin >> op >> l;
if (op == 1) {
std::cin >> r >> k >> d;
modify(1, l, l, k);
if (l + 1 <= r) modify(1, l + 1, r, d);
if (r < n) modify(1, r + 1, r + 1, -(k + d * (r - l)));
} else {
std::cout << query(1, 1, l) << '\n';
}
}
return 0;
}