分块的概念
分块(Chunking)是一种将数据或任务分解为更小的部分的思想,就是将一个区间分成几个块”。
分块算法的具体实现步骤
1.预处理部分
1.确定块的长度和块的数量
int len=sqrt(n),num=n/len;//n是总长,len是块长,num是块的数量
if(n%len!=0)num++;//n不能被len整除那么多余的要一个新的块
2. 预处理每个块的左端点和右端点
for(int i=1;i<=num;i++)//我写的是从1开始到n
{
//L[i]是块i的左端点,R[i]是块i的右端点
L[i]=(i-1)*len+1;//L[i]的上一个是R[i-1]也就是(i-1)*len
R[i]=i*len;//R[i]是R[i-1]+len
}
R[num]=n;//特殊处理最后一个块的右端点
3. 预处理每个点在哪个块
for(int i=1;i<=num;i++)
{
for(int j=L[i];j<=R[i];j++)//遍历块中的每个点
{
pos[j]=i;
}
}
4. 预处理题目要求(示例为求区间总和)
for(int i=1;i<=num;i++)
{
for(int j=L[i];j<=R[i];j++)
{
sum[i]+=a[i];//a[i]为题目给定的值
}
}
预处理部分完整代码:时间复杂度是 O ( n + n ) O(\sqrt{n}+n) O(n+n)
void init()
{
int len=sqrt(n),num=n/len;
if(n%len!=0)num++;
for(int i=1;i<=num;i++)
{
L[i]=(i-1)*len+1;
R[i]=i*len;
}
R[num]=n;
for(int i=1;i<=num;i++)
{
for(int j=L[i];j<=R[i];j++)
{
pos[i]+=a[j];
}
}
}
2.修改部分(区间增加k)
1.暴力修改
暴力查询散块,散块无法直接懒标记
void EA(int l,int r,int k)
{
for(int i=l;i<=r;i++)
{
a[i]+=k;
}
}
2.区间修改|最坏时间复杂度 O ( 3 n ) O(3\sqrt{n}) O(3n)
散块暴力,整块懒标记
void update(int l,int r,int k)
{
int p=pos[l],q=pos[r];
if(p==q)
{
EA(l,r,k);
}
else
{
EA(l,R[p]);//暴力散块
EA(L[q],r);
for(int i=p+1;i<=q+1;i++)//遍历整块
{
lazy[i]+=k;//不能覆盖之前的懒标记
}
}
}
3.查询部分
1.暴力查询
一样暴力查询散块
int query(int l,int r)//暴力查询的左端点和右端点
{
int ans=0;
for(int i=l<

最低0.47元/天 解锁文章
686

被折叠的 条评论
为什么被折叠?



