蒟蒻在刘巨佬的强烈安利下,终于学习了最弱版本的分块。
这个算法比我想的要暴力很多啊。
所谓分块,就是把一串要处理的数列分成一块一块的。
然后区间处理的时候,范围大于一个块的就区间修改整体修改,否则就暴力遍历。
也就是说每次修改的部分实际上是 左边-块-块-块……块-块-块-右边。左边右边暴力遍历。
分块是一个很宏远的算法,以至于它没有太多基本套路。
不过如何分块是我们要说一下的。这关乎到时间复杂度如何优秀过万恶卡常出题人的大计。
n个数的序列分成每块长度为m,那每次修改最坏情况自然是O(n/m+m)(块数加上暴力遍历),初中基本均值不等式看出m=sqrt(n)时明显最小。
所以分块这个套路就可以实现了。
void build(){
int block=sqrt(n);//每块长度为总数平方根
int num=n/block;//块数
if(n%block)num++;//如果除不尽还要多一个可爱的小块
for(int i=1;i<=n;i++){//处理每个数所属的块序号
belong[i]=(i-1)/block+1;
d[i]=a[i];//因题而异的操作
}
for(int i=1;i<=num;i++){//处理每个块左右端点
l[i]=(i-1)*block+1;
r[i]=i*block;
}
r[num]=n;//最后一个块右端点自然是n
for(int i=1;i<=num;i++){//因题而异的操作
sort(d+l[i],d+r[i]+1);
}
}