Balanced Lineup(分块)

原题: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);
    }
}


当然了,有查询当然要有更新了,这里直接讲一下区间更新

如果是整块的修改,那么是不是可以参照线段树的更新延迟?

对块开一个数组,每个位置代表某个块的整体更新情况

但是更新半个块就只能暴力了

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/81103036