P1438 无聊的数列

P1438 无聊的数列

题目描述

维护一个数列 ai,支持两种操作:

  • 1 l r K D:给出一个长度等于 rl+1 的等差数列,首项为 K,公差为 D,并将它对应加到 [l,r] 范围中的每一个数上。即:令 al=al+K,al+1=al+1+K+Dar=ar+K+(rl)×D

  • 2 p:询问序列的第 p 个数的值 ap

输入格式

第一行两个整数数 n,m 表示数列长度和操作个数。

第二行 n 个整数,第 i 个数表示 ai

接下来的 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% 数据,0n,m105,200ai,K,D200,1lrn,1pn

入手

在某个区间里对应加上一个等差数列。

查询第 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 @   高明y  阅读(11)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示