分块
优雅的暴力,对于一个数列,他不是一个元素一个元素处理,而是分成若干块,成块成块的处理,以此达到降低时间复杂度的目的。
需要处理的信息
首先,我们需要处理划分的块的大小—block(一般是根号n)、块的数目、每一个元素对应第几块,然后,每一块的左端点和右端点。
需要思考的问题:
- 完整的块如何处理
- 不完整的块如何处理
- 需要预处理什么东西
题解
完整的块:更新:我们用 l z [ i ] lz[i] lz[i]保存第 i i i个块整块都要加上某个数的总和。
不完整的块:更新:直接更新。
查询:返回这个数和这个数所在块的lz的和。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 5e4+100;
int a[maxn],block,n,num;
int l[maxn],r[maxn],belong[maxn],lz[maxn];
void init()
{
block = sqrt(n);
num = n/block + (n%block != 0);
for(int i=1;i<=n;i++)belong[i] = (i-1)/block + 1;
for(int i=1;i<=num;i++)
{
l[i] = (i-1)*block + 1;
r[i] = i*block;
}
r[num] = n;
}
void up(int ql,int qr,int c)
{
if(belong[ql] == belong[qr])
{
for(int i=ql;i<=qr;i++)a[i] += c;
return ;
}
for(int i=belong[ql] + 1; i <belong[qr];i++)lz[i] += c;
for(int i=ql;i<=r[belong[ql]];i++)
a[i] += c;
for(int i=l[belong[qr]];i<=qr;i++)
a[i] += c;
}
int qu(int p)
{
return a[p] + lz[belong[p]];
}
int main()
{
cin >> n;
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
init();
for(int i=1;i<=n;i++)
{
int op,ql,qr,c;
cin >> op >> ql >> qr >> c;
if(op == 1)
{
cout<<qu(qr)<<'\n';
}
else
{
up(ql,qr,c);
}
}
}