【算法#1】分块
分块我cnm我爱分块!
今天学了点分块板子,仍然不甚熟练,其中第二题就把我卡了至少一两个小时。
题外话就不说了,把板子挂在这里,本来也不是我的,但是把码风改掉了。
const int maxn=x,maxm=y;//maxm 一般为sqrt(maxn)
int n,len,num;//len:分块长度,num:分块数量。
int a[maxn],bl[maxn],l[maxm],r[maxm]; //bl[i] : i点属于哪一个分块,l,r是分块的左右点。
void build() {
cin>>n;
for(int i=1,i<=n,i++)
cin>>a[i];
len=sqrt(n);//分块长度
num=(n-1)/len+1;//分块数量
for(int i=1,i<=n,i++)
bl[i]=(i-1)/len+1;//确定每个点的归属
for(int i=1,i<=num,i++){
l[i]=(i-1)*len+1;
r[i]=i*len;//确定分块边界
}
r[num]=n;//最后一个分块端点为n!
}
void update(int l,int r,int v) {
// 修改的左右端点和传入参数。(...)看情况而定
if(bl[L]==bl[R])//如果共块
for(int i=l;i<=r;i++)
Do Something...;//直接暴力
else {
for(int i=bl[L]+1;i<=bl[R]-1;i++)
Do Something...;//这里的i枚举的是分块
for(int i=L;i<=r[bl[L]];i++)
Do Something...;// 这里的i枚举的是点
for(int i=l[bl[R]];i<=r;i++)
Do Something...;// 同上
}
}
int res(int l,int r,int v) {
// 所求的左右端点和传入参数。(...)看情况而定,和update很像。
int ans=0;
if(bl[l]==bl[r])
for(int i=L;i<=r;i++)
Do Something...;//原生态暴力
else {
for(int i=bl[l]+1;i<=bl[r]-1;i++)
Do Something...;//对块进行处理
for(int i=L;i<=r[bl[l]];i++)
Do Something...;//对左角块进行处理
for(int i=l[bl[r]];i<=r;i++)
Do Something...;//对右角块进行处理
}
return ans;
}
把板子偷来看懂了之后去做了一下LibreOJ上的数列分块模板题。
第一题没什么难度,很快就AC了。
然而,我被第二题一个不知道说是毒瘤好还是我不熟练好的一个地方卡住了,卡了大概一两个小时。
具体是这样的,我在处理result的时候,没有对给定区间整块外的那些部分加上他们所属块的标记,居然犯了这么蠢的错误,太菜了。
代码贴在了剪贴板上:Paste
明天,或者找些时间把剩下几题写了。//其他一些不是太标准的操作的模板也在代码里了
Update at 11.6
又是一如既往地被卡了一两个小时,还是没有给元素加上所在区间标记的问题……不过既然这样我是怎么拿到70分的……
for(int i=bl[l]+1;i<=bl[r]-1;i++){
int cur=lower_bound(bc[i].begin(),bc[i].end(),c-dv[i])-bc[i].begin();
if(cur)
res=max(res,bc[i][cur-1]);
}
原
for(int i=bl[l]+1;i<=bl[r]-1;i++){
int cur=lower_bound(bc[i].begin(),bc[i].end(),c-dv[i])-bc[i].begin();
if(cur)
res=max(res,bc[i][cur-1]+dv[i]);
}
现
我找你找得好苦啊!下次再犯,我就……我就……什么也不干
下午切了分块4,还是被卡了一会,不过有了之前的经验这次错误很快就找到了。
原题要求我们做区间加法和区间求和,我虽然对区间做了标记,也在处理元素的时候加上了标记,但是,在对区间求和的时候加上的值应当是标记乘以这个区间的长度,我却只加了一个导致爆零两次……