无聊的数列
题目背景
无聊的 YYB 总喜欢搞出一些正常人无法搞出的东西。有一天,无聊的 YYB 想出了一道无聊的题:无聊的数列。。。
题目描述
维护一个数列 a i a_i ai,支持两种操作:
-
1 l r K D
:给出一个长度等于 r − l + 1 r-l+1 r−l+1 的等差数列,首项为 K K K,公差为 D D D,并将它对应加到 [ l , r ] [l,r] [l,r] 范围中的每一个数上。即:令 a l = a l + K , a l + 1 = a l + 1 + K + D … a r = a r + K + ( r − l ) × D a_l=a_l+K,a_{l+1}=a_{l+1}+K+D\ldots a_r=a_r+K+(r-l) \times D al=al+K,al+1=al+1+K+D…ar=ar+K+(r−l)×D。 -
2 p
:询问序列的第 p p p 个数的值 a p a_p ap。
输入格式
第一行两个整数 n , m n,m n,m 表示数列长度和操作个数。
第二行 n n n 个整数,第 i i i 个数表示 a i a_i ai。
接下来的 m m m 行,每行先输入一个整数 o p t opt opt。
若 o p t = 1 opt=1 opt=1 则再输入四个整数 l r K D l\ r\ K\ D l r K D;
若 o p t = 2 opt=2 opt=2 则再输入一个整数 p p p。
输出格式
对于每个询问,一行一个整数表示答案。
样例 #1
样例输入 #1
5 2
1 2 3 4 5
1 2 4 1 2
2 3
样例输出 #1
6
提示
数据规模与约定
对于 100 % 100\% 100% 数据, 0 ≤ n , m ≤ 1 0 5 , − 200 ≤ a i , K , D ≤ 200 , 1 ≤ l ≤ r ≤ n , 1 ≤ p ≤ n 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 0≤n,m≤105,−200≤ai,K,D≤200,1≤l≤r≤n,1≤p≤n。
原题
思路
对区间 [ l , r ] [l,r] [l,r] 加上一个首项为 k k k 公差为 d d d 的等差数列,相当于这个区间加上 k − d ∗ l k-d*l k−d∗l 以及各个位置加上下标乘以公差即 i d x ∗ d idx*d idx∗d。那么我们只需要用线段树维护两个标记 sum1 和 sum2 即可。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
int n, m;
#define lc p << 1
#define rc p << 1 | 1
const int maxn = 1e5 + 6;
i64 a[maxn];
struct node
{
i64 l, r, sum1, sum2;
} tr[maxn * 4];
void build(int p, int l, int r) // p是当前位置,l和r表示区间
{
if (l == r)
{
tr[p] = {l, r, 0, 0};
return;
}
int mid = l + r >> 1;
build(lc, l, mid);
build(rc, mid + 1, r);
tr[p] = {l, r, tr[lc].sum1 + tr[rc].sum1, tr[lc].sum2 + tr[rc].sum2};
}
void update(int p, int l, int r, i64 add1, i64 add2) // 区间加数
{
if (l <= tr[p].l && r >= tr[p].r)
{
tr[p].sum1 += add1;
tr[p].sum2 += add2;
return;
}
int mid = tr[p].l + tr[p].r >> 1;
if (l <= mid)
update(lc, l, r, add1, add2);
if (r >= mid + 1)
update(rc, l, r, add1, add2);
}
i64 query(int p, int x, i64 sum1, i64 sum2) // p是当前位置,x表示查询位置
{
if (tr[p].l == tr[p].r)
{
return tr[p].sum1 + sum1 + (tr[p].sum2 + sum2) * (i64)tr[p].l; // 处理等差数列的关键所在
}
int mid = tr[p].l + tr[p].r >> 1;
if (x <= mid)
return query(lc, x, sum1 + tr[p].sum1, sum2 + tr[p].sum2);
else
return query(rc, x, sum1 + tr[p].sum1, sum2 + tr[p].sum2);
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
}
build(1, 1, n);
while (m--)
{
int op;
cin >> op;
if (op == 1)
{
int l, r, k, d;
cin >> l >> r >> k >> d;
update(1, l, r, k - d * l, d);
}
else
{
int x;
cin >> x;
cout << query(1, x, 0, 0) + a[x] << '\n';
}
}
return 0;
}