原题传送门
区间加等差数列,单点求和,可以用树状数组维护
开两个树状数组,第一个维护和,第二个维护
d
e
l
t
a
delta
delta
魔改暴力加等差数列的方式,用树状数组只加
l
o
g
n
logn
logn个地方,但我需要保存
d
e
l
t
a
delta
delta,求和的时候,累计和与
k
∗
d
e
l
t
a
k*delta
k∗delta,这个
k
k
k就是实际意义上的要求的第
x
x
x个数和当前的差
懂了具体操作之后,就知道如何更新了
u
p
d
a
t
e
(
l
,
k
,
d
)
,
u
p
d
a
t
e
(
r
+
1
,
−
k
−
(
r
−
l
+
1
)
∗
d
,
−
d
)
update(l,k,d),update(r+1,-k-(r-l+1)*d,-d)
update(l,k,d),update(r+1,−k−(r−l+1)∗d,−d)
Code:
#include <bits/stdc++.h>
#define maxn 100010
using namespace std;
int n, m, a[maxn], tree[maxn][2];
inline int read(){
int s = 0, w = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') w = -1;
for (; isdigit(c); c = getchar()) s = (s << 1) + (s << 3) + (c ^ 48);
return s * w;
}
int lowbit(int x){ return x & -x; }
void update(int x, int k, int d){ for (; x <= n; x += lowbit(x)) tree[x][0] += k, tree[x][1] += d, k += d * lowbit(x); }
int query(int x){ int s = 0, p = x; for (; x; x -= lowbit(x)) s += tree[x][0] + (p - x) * tree[x][1]; return s; }
int main(){
n = read(), m = read();
for (int i = 1; i <= n; ++i) a[i] = read();
while (m--){
int opt = read();
if (opt == 1){
int l = read(), r = read(), k = read(), d = read();
update(l, k, d), update(r + 1, -k - (r - l + 1) * d, -d);
} else{
int x = read();
printf("%d\n", query(x) + a[x]);
}
}
return 0;
}