【POJ 3264】平衡的阵容【分块】

版权声明:若希望转载,在评论里直接说明即可,谢谢! https://blog.csdn.net/SSL_ZYC/article/details/82729886

题目大意:

题目链接:http://poj.org/problem?id=3264
给出一个长度为 n 的数列,求第 l 位到第 r 位的最大值减最小值。


思路:

RMQ做法:https://blog.csdn.net/SSL_ZYC/article/details/80422589
这道题也可以用分块做。当然线段树主席树也都可以。
简直比分块模板还简单。因为没有修改操作。
要求 l r 之间的最小值,那么就先将这个数列分成 n 块,每块初始化出一个最大值和最小值,时间复杂度 O ( n )
接着对于每次询问,就用分块求出询问区间的最大值和最小值,再两者相减,即为答案。


代码:

此代码在POJ上可以AC,但洛谷只能拿40分,应该是编译环境的问题。

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#define N 50100
using namespace std;

int n,m,a[N],t,x,y,L[N],R[N],pos[N],maxn[N],minn[N];

int find_max(int l,int r)  //暴力求l到r之间的最大值
{
    int ans=0;
    for (int i=l;i<=r;i++)
     ans=max(ans,a[i]);
    return ans;
}

int find_min(int l,int r)  //暴力求l到r之间的最小值
{
    int ans=1e9;
    for (int i=l;i<=r;i++)
     ans=min(ans,a[i]);
    return ans;
}

int Max(int l,int r)  //求询问区间的最大值
{
    int q=pos[l],p=pos[r];
    if (q==p) return find_max(l,r);
    int ans=max(find_max(l,R[q]),find_max(L[p],r));
    for (int i=q+1;i<p;i++)
     ans=max(ans,maxn[i]);
    return ans;
}

int Min(int l,int r)  //求询问区间的最小值
{
    int q=pos[l],p=pos[r];
    if (q==p) return find_min(l,r);
    int ans=min(find_min(l,R[q]),find_min(L[p],r));
    for (int i=q+1;i<p;i++)
     ans=min(ans,minn[i]);
    return ans;
}

int ask(int l,int r)
{
    return Max(l,r)-Min(l,r);
}

int main()
{
    memset(minn,0x3f3f3f3f,sizeof(minn));
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
     scanf("%d",&a[i]);
    t=(int)sqrt(n);
    for (int i=1;i<=t;i++)
    {
        L[i]=R[i-1]+1;
        R[i]=i*t;
    }
    if (R[t]<n)
    {
        L[++t]=R[t-1]+1;
        R[t]=n;
    }
    for (int i=1;i<=t;i++)
     for (int j=L[i];j<=R[i];j++)
     {
        pos[j]=i;
        maxn[i]=max(maxn[i],a[j]);
        minn[i]=min(minn[i],a[j]);  //初始化每个区间的最大值和最小值
     }
    while (m--)
    {
        scanf("%d%d",&x,&y);
        printf("%d\n",ask(x,y));
    }
    return 0;
} 

猜你喜欢

转载自blog.csdn.net/SSL_ZYC/article/details/82729886
今日推荐