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;
}
posted @ 2024-06-03 19:46  高明y  阅读(19)  评论(0)    收藏  举报