[POJ]3264 Balanced Lineup
问题
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 2Sample Output
6
3
0
分析
题目大意是一个农夫有好多奶牛,假设这些奶牛已经排好队了而且还编了号,现在这个农夫很无聊就想玩个游戏,算算连续编号内的奶牛的最大身高差,真够闲的。。大概好像是这个意思。
属于RMQ问题。解法有三种,1)朴素法; 2)线段树; 3)ST
其中朴素法耗时过长,没有通过 T_T
采用了线段树法。以题中数据为例,可以构建如下图的树:
叶子节点即为输入的数据,非叶子结点保存中间的最大值与最小值,这样做在搜索时可以保证不需要每次都遍历到根节点,在大数据查找时可以大大降低复杂度。
如输入2,5。查找从根节点开始,(2,5)划分为(2,3),(4,5)两个区间,(2,3)又可以划分为(2,2),(3,3)两个区间,分别得到最大值为7,最小值为3;(4,5)直接在节点6中得到区间最大值为4,最小值为2。因此(2,5)最大值为7,最小值为2,差值为5
源代码
#include <cstdio>
#include <algorithm>
using namespace std;
struct node
{
int max, min, l, r;
};
node tree[200000];
int h[50005];
int m_max, m_min;
void init(int l, int r, int root)
{
tree[root].l = l;
tree[root].r = r;
if (l == r)
{
tree[root].max = h[l];
tree[root].min = h[l];
return;
}
int mid = (l + r) >> 1;
init(l, mid, root * 2);
init(mid + 1, r, root * 2 + 1);
tree[root].max = max(tree[2 * root].max, tree[2 * root + 1].max);
tree[root].min = min(tree[2 * root].min, tree[2 * root + 1].min);
}
void findit(int l, int r, int root)
{
if (tree[root].l == l && tree[root].r == r)
{
m_max = max(m_max, tree[root].max);
m_min = min(m_min, tree[root].min);
return;
}
int mid = (tree[root].l + tree[root].r) >> 1;
if (mid >= r)
findit(l, r, root * 2);
else if (mid<l)
findit(l, r, root * 2 + 1);
else
{
findit(l, mid, root * 2);
findit(mid + 1, r, root * 2 + 1);
}
}
int main()
{
int N, Q, x, y;
scanf("%d%d", &N, &Q);
for (int i = 1; i <= N; i++)
scanf("%d", &h[i]);
init(1, N, 1);
while (Q--)
{
m_max = 0;
m_min = 99999999;
scanf("%d%d", &x, &y);
findit(x, y, 1);
printf("%d\n", m_max - m_min);
}
return 0;
}
程序结果
Result | Memory | Time | Language | Code Length |
---|---|---|---|---|
Accepted | 2400K | 1750MS | C++ | 1175B |
还是好久 T_T, 被第一名 250MS的大神甩出不知道多少条街。。。