#6277. 数列分块入门 1 link
考虑将n个数分成blo块分别处理。
分块的思想:“整块打标机,小块暴力处理。”
b
y
V
i
k
t
l
e
y
\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;\;by\;\;Viktley
byViktley
根据均值不等式,我们将原序列分成
n
\sqrt n
n块的时间复杂度最低。
我们给每个块设置一个加法标记(就是记录这个块中元素一起加了多少),
每次操作对每个整块直接O(1)标记,而不完整的块由于元素比较少,暴力修改元素的值。
每次询问时返回元素的值加上其所在块的加法标记。
#include <cstdio>
#include <iostream>
#include <cmath>
using namespace std;
typedef long long ll;
const int N = 5e4 + 10;
ll n, a[N], add[N], blo, bl[N], op, x, y, z;
inline ll read()
{
char c = getchar();
ll x = 0, f = 1;
while(c < '0' || c > '9')
{
if(c == '-') f = -f;
c = getchar();
}
while(c >= '0' && c <= '9') x = x * 10 + (c - 48), c = getchar();
return x * f;
}
inline void update(ll x, ll y, ll z)
{
for(ll i = x; i <= min(bl[x] * blo, y); i++) a[i] += z;
if(bl[x] != bl[y])
for(ll i = (bl[y] - 1) * blo + 1; i <= y; i++) a[i] += z;
for(ll i = bl[x] + 1; i <= bl[y] - 1; i++) add[i] += z;
}
int main()
{
// freopen("a.txt", "r", stdin);
// freopen("c.txt", "w", stdout);
n = read();
blo = ll(sqrt(n));
for(ll i = 1; i <= n; i++) a[i] = read(), bl[i] = (i - 1) / blo + 1;
for(ll i = 1; i <= n; i++)
{
op = read(), x = read(), y = read(), z = read();
if(!op) update(x, y, z);
else printf("%lld\n", a[y] + add[bl[y]]);
}
return 0;
}