题解:P13976 数列分块入门 1
:::epigraph[Shellchen] 大家好呀,今天我来给大家讲分块! :::
分块是一种数据结构,通过把数列分成若干块来处理问题。区间加法,单点查询是分块最基本的一种问题。
分块的过程如下:
首先我们需要有一个数列,把它分成若干个等长的块。最后一块可以稍短。就像这样:
1 4 7/2 5 8/3 6 9/10 12
接下来,我们可以这么处理区间加法:先给范围内所有完整的块加上
这里需要用到一个 trick:懒标记思想。我们只需要对于中间所有完整块打上一个标记,就代表整个块加上了这个数,之后单点查值的时候就可以用单点的值加上这个 tag 了。不是完整块的部分暴力加即可。
那么,如何找完整块呢?设块长为
这样下来,修改复杂度是
最后,要是还没有看懂,那就只能上绝招了,上代码!
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=3e5+10,mod=1e9+7;
int a[N],tag[N];
signed main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
int k=sqrt(n);
for(int i=1;i<=n;i++)
{
int op,l,r,c;
cin>>op>>l>>r>>c;
if(op==0)
{
int i=l;
for(;i%k!=1&&i<=r;i++) a[i]+=c;
for(;i<=r-k;i+=k) tag[i]+=c;
for(;i<=r;i++) a[i]+=c;
}
else
{
int i=r;
for(;i%k!=1;i--);
cout<<a[r]+tag[i]<<'\n';
}
}
return 0;
}
完结撒花。
:::epigraph[Shellchen] 讲完了,下课! :::