在某大佬的帮助下我今天get到了分块
简单来说分块就是可以把块分成某些奇怪的大小,使之达到优秀的复杂度。but我现在只会把块分成根号大小,然后我们修改一个点的
信息时就可以顺便修改次点所在块的信息(O(1))。接着当我们查询[L,R]这段区间,的时候,对于中间的大块可以直接拿来用,对于两
边不完整的块则直接暴力查询(都是根号n,)。
差不多就这样,最后附上DCOJ 1324用分块过的代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=1e5+7;
int num,block,l[maxn],r[maxn],n,m,p,x,t,belong[maxn];
long long Max[maxn],a[maxn];
void build()
{
block=sqrt(n);//块的太小
num=n/block;
if(n%block) num++;//块的个数,记得特判
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<=n;i++) belong[i]=(i-1)/block+1;//确定每个 点所属的块
for(int i=1;i<=num;i++)
for(int j=l[i];j<=r[i];j++)
Max[i]=max(Max[i],a[j]);//预处理
}
void update(int x,int date)//单点更改
{
a[x]+=date;
Max[belong[x]]=max(Max[belong[x]],a[x]);
}
long long ask(int x,int y)//区间查询
{
long long ans=0;
if(belong[x]==belong[y])
{
for(int i=x;i<=y;i++)
{
ans=max(ans,a[i]);
}
return ans;
}//如果左右端点在同一块内则直接暴力查询
for(int i=x;i<=r[belong[x]];i++)
ans=max(ans,a[i]);
for(int i=belong[x]+1;i<belong[y];i++)
ans=max(ans,Max[i]);//如果左右端点需跨块,那么对于中间大块的信息直接使用
for(int i=l[belong[y]];i<=y;i++)
ans=max(ans,a[i]);// 两端不完整的的块暴力查询
return ans;
}
int main()
{
scanf("%d",&n);
build();
scanf("%d",&m);
while(m--)
{
scanf("%d%d%d",&t,&p,&x);
if(t==1) update(p,x);
else printf("%lld\n",ask(p,x));
}
return 0;
}
以上 by LQ_double
完结散花
分块算法详解

333

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



