分块思想:
本质上是暴力,但是用一种巧妙的办法将要暴力的长度为 n n n 的区间划分为 n \sqrt n n块,并在每一个块中进行总体打标记,最后结果就是将各个标记统一运算。
1、区间修改单点查询 - 代码
#include <algorithm>
#include <cctype>
#include <climits>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <queue>
#include <string>
#include <utility>
#define Mp(X, Y) std::make_pair(X, Y)
#define debug(X) std::cout << #X << " : " << X << std::endl
#define lson ((rt) << (1))
#define rson ((rt) << 1 | 1)
#define mid (l + r >> 1)
#define lowbit(X) ((X) & (-X))
typedef long long ll;
typedef std::pair<int, int> pii;
ll nextInt()
{
ll num = 0;
char c;
bool flag = false;
while ((c = std::getchar()) == ' ' || c == '\r' || c == '\t' || c == '\n');
if (c == '-')
flag = true;
else
num = c - 48;
while (std::isdigit(c = std::getchar()))
num = num * 10 + c - 48;
return (flag ? -1 : 1) * num;
}
const size_t _Siz = 114514;
int L[_Siz] = { 0 }, R[_Siz] = { 0 }, a[_Siz] = { 0 }, pos[_Siz] = { 0 }, add[_Siz] = { 0 };
void change(const int l, const int r, const int c)
{
int ql = pos[l], qr = pos[r];
if (ql == qr)
{
for (int i = l; i <= r; i++)
a[i] += c;
}
else
{
for (int i = l; i <= R[ql]; i++)
a[i] += c;
for (int i = L[qr]; i <= r; i++)
a[i] += c;
for (int i = ql + 1; i <= qr - 1; i++)
add[i] += c;
}
}
int main(int argc, char **argv)
{
int n = nextInt();
for (int i = 1; i <= n; i++)
a[i] = nextInt();
// 分成sqrt(n)块
int t = std::sqrt(n);
for (int i = 1; i <= t; i++)
{
L[i] = (i - 1) * t + 1;
R[i] = i * t + 1;
}
if (R[t] < n)
{
t++;
L[t] = R[t - 1] + 1;
R[t] = n;
}
// 标位置
for (int i = 1; i <= t; i++)
for (int j = L[i]; j <= R[i]; j++)
pos[j] = i;
// 主体
for (int i = 1; i <= n; i++)
{
int opt = nextInt(), l = nextInt(), r = nextInt(), c = nextInt();
if (!opt)
{
// int c = nextInt();
change(l, r ,c);
}
else
{
int q = pos[r];
std::cout << add[q] + a[r] << "\n";
}
}
return 0;
}