POJ3264 Balanced Lineup (区间查询最大值、最小值)

题目链接

http://poj.org/problem?id=3264
给你一个长度为n的序列a[N] (1 ≤ N ≤ 50000),询问Q(1 ≤ Q ≤ 200000) 次,每次输出[L, R]区间最大值与最小值的差是多少。

Input
多组用例
第一行是两个整数 N,Q
然后是N个数a[i] 保证a[i] 都小于1e9
然后是Q个询问 每次给你L,R 保证(1<=L<=R<= N)
Output
输出每次询问[L, R]区间最大值与最小值的差是多少
Sample Input
6 3
1
7
3
4
2
5
1 5
4 6
2 2
Sample Output
6
3
0

分析

区间查询最大值、最小值。线段树裸题,没啥坑点。
5月份的第50篇博客,完美AC。

AC代码

//2157ms 2.4MB
#include <cstdio>
#include <algorithm>
#define inf 0x3f3f3f3f
#define lson p<<1
#define rson p<<1|1
using namespace std;
const int maxn=5e4+100;
struct node
{
    int l,r;//结点所维护的区间
    int mx,mn;//区间信息
}T[maxn<<2];//线段树要开四倍空间
int a[maxn];

void up(int p)
{
    //区间信息的维护,将左子树所表示的区间与右子树所表示的区间合并
    T[p].mx=max(T[lson].mx,T[rson].mx); //以维护最大值举例
    T[p].mn=min(T[lson].mn,T[rson].mn);
}

void build(int p,int l,int r)//p表示结点编号,l、r表示结点p所表示的区间
{
    T[p].l=l,T[p].r=r;//确定结点p所表示的区间[l,r]
    if(l==r) //确定叶子结点所表示的信息
    {
        //T[p].num=a[l];
        T[p].mx=T[p].mn=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(lson,l,mid); //递归创建左子树
    build(rson,mid+1,r); //递归创建右子树
    up(p); //由下向上传递信息,即由两个小区间合并成一个大区间

}

int query_mx(int p,int x,int y)
{
    if(x==T[p].l && y==T[p].r) //区间[x,y]恰好与结点p所表示的区间重合
        return T[p].mx;//这个结点所表示的区间信息是所需要的
    int mid=(T[p].l+T[p].r)>>1;
    int ans=-inf;
    //down(p);
    if(y<=mid) //区间[x,y]一定在p的左子树上
        return max(ans,query_mx(lson,x,y));
    else if(x>mid) //区间[x,y]一定在p的右子树上
        return max(ans,query_mx(rson,x,y));
    else //没有与区间[x,y]恰好重合的结点
    {
        //将区间[x,y]分成两个小区间[x,mid]和[mid+1,y]
        //[x,mid]一定在p的左子树上
        //[mid+1,y]一定在p的右子树上
        ans=max(ans,query_mx(lson,x,mid));
        ans=max(ans,query_mx(rson,mid+1,y));
        return ans;
    }
}
int query_mn(int p,int x,int y)
{
    if(x==T[p].l && y==T[p].r) //区间[x,y]恰好与结点p所表示的区间重合
        return T[p].mn;//这个结点所表示的区间信息是所需要的
    int mid=(T[p].l+T[p].r)>>1;
    //down(p);
    int ans=inf;
    if(y<=mid) //区间[x,y]一定在p的左子树上
        return min(ans,query_mn(lson,x,y));
    else if(x>mid) //区间[x,y]一定在p的右子树上
        return min(ans,query_mn(rson,x,y));
    else //没有与区间[x,y]恰好重合的结点
    {
        //将区间[x,y]分成两个小区间[x,mid]和[mid+1,y]
        //[x,mid]一定在p的左子树上
        //[mid+1,y]一定在p的右子树上
        ans=min(ans,query_mn(lson,x,mid));
        ans=min(ans,query_mn(rson,mid+1,y));
        return ans;
    }
}

int main()
{
    int n,m;
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,1,n);
        while(m--)
        {
            int x,y;
            scanf("%d%d",&x,&y);
            printf("%d\n",query_mx(1,x,y)-query_mn(1,x,y));
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37685156/article/details/80530395