P1438 无聊的数列

题目背景

无聊的YYB总喜欢搞出一些正常人无法搞出的东西。有一天,无聊的YYB想出了一道无聊的题:无聊的数列。。。(K峰:这题不是傻X题吗)

题目描述

维护一个数列{a[i]},支持两种操作:

1、1 L R K D:给出一个长度等于R-L+1的等差数列,首项为K,公差为D,并将它对应加到a[L]~a[R]的每一个数上。即:令a[L]=a[L]+K,a[L+1]=a[L+1]+K+D,

a[L+2]=a[L+2]+K+2D……a[R]=a[R]+K+(R-L)D。

2、2 P:询问序列的第P个数的值a[P]。

输入输出格式

输入格式:

 

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

第二行n个整数,第i个数表示a[i](i=1,2,3…,n)。

接下来的m行,表示m个操作,有两种形式:

1 L R K D

扫描二维码关注公众号,回复: 1550289 查看本文章

2 P 字母意义见描述(L≤R)。

 

输出格式:

 

对于每个询问,输出答案,每个答案占一行。

 

输入输出样例

输入样例#1: 复制
5 2
1 2 3 4 5
1 2 4 1 2
2 3
输出样例#1: 复制
6

说明

数据规模:

0≤n,m≤100000

|a[i]|,|K|,|D|≤200

Hint:

有没有巧妙的做法?

总结:线段树来做

考虑维护差分数组

a[l....r] 加上一个公差为d, 首项为k的等差数列

则相当于差分数组 

1. c[l] += k, c[r + 1] -= k

2. c[i] += d (l + 1 <= i <= r)

3. c[r + 1] -= (r - l) * d

第一个好理解吧, 每个数都加了k

第二个,相当于每一项加的都比前一项多加d

第三项,相当于a[r] 加了 (r - l) * d,而 a[r + 1]没变

注意边界问题

#include <bits/stdc++.h>

using namespace std;
const int maxn = 4e5 + 7;
int n, m, a[maxn], sum[maxn], laz[maxn], val[maxn];
void update(int o) {
	val[o] = val[o << 1] + val[o << 1 | 1];
}
void pushdown(int o, int l, int r) {
	if(laz[o] != 0) {
		int mid = (l + r) >> 1; 
		laz[o << 1] += laz[o];
		laz[o << 1 | 1] += laz[o];
		val[o << 1] += (mid - l + 1) * laz[o];
		val[o << 1 | 1] += (r - mid) * laz[o];
		laz[o] = 0;
	}
}
void build(int o, int l, int r) {
	if(l == r) {
		val[o] = sum[l]; return;
	} int mid = (l + r) >> 1;
	build(o << 1, l, mid); build(o << 1 | 1, mid + 1, r);
	update(o);
}
void modify(int o, int l, int r, int ql, int qr, int z) {
	if(ql <= l && r <= qr) {
		val[o] += (r - l + 1) * z; laz[o] += z; return;
	} int mid = (l + r) >> 1;
	pushdown(o, l, r);
	if(ql <= mid) modify(o << 1, l, mid, ql, qr, z);
	if(qr > mid) modify(o << 1 | 1, mid + 1, r, ql, qr, z);
	update(o);
}
int query(int o, int l, int r, int ql, int qr) {
	if(ql <= l && r <= qr) return val[o];
	int res = 0, mid = (l + r) >> 1;
	pushdown(o, l, r);
	if(ql <= mid) res += query(o << 1, l, mid, ql, qr);
	if(qr > mid) res += query(o << 1 | 1, mid + 1, r, ql, qr);
	return res;
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), sum[i] = a[i] - a[i - 1];
	build(1, 1, n);
	while(m--) {
		int opt, l, r, k, d, p;
		scanf("%d", &opt);
		if(opt == 1) {
			scanf("%d%d%d%d", &l, &r, &k, &d);
			if(r < n) modify(1, 1, n, r + 1, r + 1, -(k + d * (r - l)));
			modify(1, 1, n, l, l, k); if(l < r) modify(1, 1, n, l + 1, r, d);
		} else scanf("%d", &p), printf("%d\n", query(1, 1, n, 1, p));
	}
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/oi-forever/p/9163766.html
今日推荐