原题:POJ - 3264
题意:
给一个数组,每次询问一个区间的最大值和最小值
解析:
一般来说是用线段树来做这类问题的,不过在数据比较小的时候可以用分块做
对于长度为n的数组,我们可以分成多个连续的块,对每个块预处理相应的最小值和最大值。比如一个块长度k为5,求2~17时我们就只需要遍历2~5,16~17,中间的就用预处理出的数据就行
而且,k取sqrt(n)的时候,块外的遍历和块间的遍历复杂度之和最小
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
int a[50009];
int ma[5000],mi[5000];
int k;
int idx(int p){所在块下标
return (p-1)/k+1;
}
int main(){
mmm(ma,0),mmm(mi,125);
int n=read(),q=read();
for1(i,1,n)scanf("%d",&a[i]);
k=(int)sqrt(n);
for(int i=1;i<=n;i++){
ma[idx(i)]=max(ma[idx(i)],a[i]);
mi[idx(i)]=min(mi[idx(i)],a[i]);
}
while(q--){
int l=read(),r=read();
int ansma=0,ansmi=1e9;
if(idx(r)!=idx(l)){
for(int i=l;i<=min(n,idx(l)*k);i++)
ansma=max(ansma,a[i]),
ansmi=min(ansmi,a[i]);
for(int i=(idx(r)-1)*k+1;i<=r;i++)
ansma=max(ansma,a[i]),
ansmi=min(ansmi,a[i]);
for(int i=idx(l)+1;i<idx(r);i++)
ansma=max(ansma,ma[i]),
ansmi=min(ansmi,mi[i]);
}
else{
for(int i=l;i<=r;i++)
ansma=max(ansma,a[i]),
ansmi=min(ansmi,a[i]);
}
printf("%d\n",ansma-ansmi);
}
}
当然了,有查询当然要有更新了,这里直接讲一下区间更新
如果是整块的修改,那么是不是可以参照线段树的更新延迟?
对块开一个数组,每个位置代表某个块的整体更新情况
但是更新半个块就只能暴力了