POJ 3264:Balanced Lineup(线段树应用:区间最大值与最小值之差)

POJ 3264:Balanced Lineup(线段树应用:区间最大值与最小值之差)


题目链接:POJ 3264


Description


For the daily milking, Farmer John’s N cows (1 ≤ N ≤ 50,000) always line up in the same order. One day Farmer John decides to organize a game of Ultimate Frisbee with some of the cows. To keep things simple, he will take a contiguous range of cows from the milking lineup to play the game. However, for all the cows to have fun they should not differ too much in height.

Farmer John has made a list of Q (1 ≤ Q ≤ 200,000) potential groups of cows and their heights (1 ≤ height ≤ 1,000,000). For each group, he wants your help to determine the difference in height between the shortest and the tallest cow in the group.


Input


Line 1: Two space-separated integers, N and Q.
Lines 2…N+1: Line i+1 contains a single integer that is the height of cow i
Lines N+2…N+Q+1: Two integers A and B (1 ≤ A ≤ B ≤ N), representing the range of cows from A to B inclusive.


Output


Lines 1…Q: Each line contains a single integer that is a response to a reply and indicates the difference in height between the tallest and shortest cow in the range.


Sample Input


6 3
1
7
3
4
2
5
1 5
4 6
2 2


Sample Output


6
3
0

题目大意:给定n,q分别表示区间的大小为:n,后跟着q次查询;求得给定区间最大值与最小值之差,暴力绝对不行,线段树简单应用

ps:感觉第二个代码容易懂

代码一如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0xffffff0;
const int maxN=200010;
int minV=INF;
int maxV=-INF;     //表示某一区间内最大值、最小值

/**结点结构*/
struct Node
{
    int L,R;
    int minV,maxV;
    int Mid;
    /**如果防止内存超限的话可以
    int Mid()
    {
        return (L+R)/2;
    }*/
};
/**用数组代替指针存放树结构(只需保证数组大小为结点数4倍即可)*/
Node tree[4*maxN];

/**建立线段树*/
void build_Tree(int root,int L,int R)
{
    tree[root].L=L;
    tree[root].R=R;

    /*如果用第二种方法的话,这条语句就该去掉*/
    tree[root].Mid=(tree[root].L+tree[root].R)/2;

    tree[root].minV=INF;
    tree[root].maxV=-INF;
    if(L!=R)
    {
        build_Tree(2*root,L,(L+R)/2);
        build_Tree(2*root+1,(L+R)/2+1,R);
    }
}

/**插入数据(将第i个数,其值为v,插入线段树)*/
void Insert(int root,int i,int v)
{
    if(tree[root].L==tree[root].R)
    {
        tree[root].minV=tree[root].maxV=v;
        return;
    }
    tree[root].minV=min(tree[root].minV,v);
    tree[root].maxV=max(tree[root].maxV,v);
    if(i<=tree[root].Mid)
        Insert(2*root,i,v);
    else
        Insert(2*root+1,i,v);
}

/**查询(查询区间[s,e]中的最小值和最大值,如果更优就记在全局变量minV,maxV里*/
void Query(int root,int s,int e)
{
    if(tree[root].minV>=minV&&tree[root].maxV<=maxV)
        return ;
    if(tree[root].L==s&&tree[root].R==e)
    {
        minV=min(minV,tree[root].minV);
        maxV=max(maxV,tree[root].maxV);
        return;
    }
    /**区间过大*/
    if(e<=tree[root].Mid)
        Query(2*root,s,e);
    else if(s>tree[root].Mid)
        Query(2*root+1,s,e);
    /**左右子树*/
    else
    {
        Query(2*root,s,tree[root].Mid);
        Query(2*root+1,tree[root].Mid+1,e);
    }
}
int main()
{
    int n,q;
    int num;
    scanf("%d%d",&n,&q);
    build_Tree(1,1,n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&num);
        Insert(1,i,num);
    }
    for(int i=1;i<=q;i++)
    {
        int s,e;         //待查询区间起终点
        scanf("%d%d",&s,&e);
        minV=INF;
        maxV=-INF;
        Query(1,s,e);
        printf("%d\n",maxV-minV);
    }
    return 0;
}

另附第二种代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

const int INF=0xffffff0;     //确定一个最大值
const int maxn=50010;      //n的最大值
/**结点结构*/
struct Node
{
    int L,R;
    int minV,maxV;
};

Node tree[4*maxn];        //用数组表示线段树
int a[maxn];             //存放结点数值

int maxV=-INF;
int minV=INF;      //存放最大值与最小值

/**建立线段树,并赋初值*/
void build_Tree(int root,int L,int R)
{
    tree[root].L=L;
    tree[root].R=R;
    /**到叶子结点时附值*/
    if(L==R)
    {
        tree[root].maxV=tree[root].minV=a[L];
        return ;
    }

    int mid=(tree[root].L+tree[root].R)/2;
    build_Tree(2*root,L,mid);
    build_Tree(2*root+1,mid+1,R);

    tree[root].minV=min(tree[2*root].minV,tree[2*root+1].minV);
    tree[root].maxV=max(tree[2*root].maxV,tree[2*root+1].maxV);          //当不是叶子结点时,存放左右孩子的最大值与最小值
}
/**查询区间[s,e]中的最大值与最小值*/
void  Query(int root,int s,int e)
{
    if(minV<=tree[root].minV&&maxV>=tree[root].maxV)
        return;

    /**当刚好区间相等时*/
    if(tree[root].L==s&&tree[root].R==e)
    {
        minV=min(minV,tree[root].minV);
        maxV=max(maxV,tree[root].maxV);
        return ;
    }

    int mid=(tree[root].L+tree[root].R)/2;
    /**区间过大时*/
    if(e<=mid)
        Query(2*root,s,e);
    else if(s>mid)
        Query(2*root+1,s,e);
    /**左右孩子*/
    else
    {
        Query(2*root,s,mid);
        Query(2*root+1,mid+1,e);
    }
}
int main()
{
    int n,q;
    int num;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }

    build_Tree(1,1,n);

    int s,e;
    for(int i=1;i<=q;i++)
    {
        minV=INF;
        maxV=-INF;
        scanf("%d%d",&s,&e);
        Query(1,s,e);
        printf("%d\n",maxV-minV);
    }
    return 0;
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值