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 2
Sample Output
6
3
0
线段树,也叫区间树(interval tree),它在各个节点保存一条线段(即子数组)。设数列A 包含
N 个元素,则线段树的根节点表示整个区间A[1;N],左孩子表示区间A[1; (1 + N)/2],右孩子表
示区间A[(1 + N)/2 + 1;N],不断递归,直到叶子节点,叶子节点只包含一个元素。
线段树有如下特征:
• 线段树是一棵完全二叉树
• 线段树的深度不超过logL, L 是区间的长度
• 线段树把一个长度为L 的区间分成不超过2 logL 条线段
线段树的基本操作有构造线段树、区间查询和区间修改。
线段树通常用于解决和区间统计有关的问题。比如某些数据可以按区间进行划分,按区间动态
进行修改,而且还需要按区间多次进行查询,那么使用线段树可以达到较快的查询速度。
用线段树解题,关键是要想清楚每个节点要存哪些信息(当然区间起点和终点,以及左右孩子
指针是必须的���,以及这些信息如何高效查询,更新。不要一更新就更新到叶子节点,那样更新操作
的效率最坏有可能O(N) 的。
用数组存储完全二叉树,可以使速度更快~
#include <iostream>
#include <vector>
#include <algorithm>
#include<map>
#include<vector>
#include<queue>
#include<string>
#include<set>
#include<cmath>
#include<cstdio>
#include<sstream>
#include<cstring>
//#pragma warning(disable:4996)
using namespace std;
#define MAXN 50001
#define INF 0x7fffffff;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define L(a) ((a)<<1)
#define R(a) (((a)<<1)+1)
//数组存储线段树
typedef struct node_t {
int left, right;
int maxx, minx;
} node_t;
int a[MAXN];
node_t node[MAXN * 4];
int minx, maxx;
void init() {
memset(node, 0, sizeof(node));
}
//以t为根节点,为区间l,r建立线段树
void build(int t, int l, int r) {
node[t].left = l, node[t].right = r;
if (l == r) {
node[t].maxx = node[t].minx = a[l];
return;
}
const int mid = (l + r) / 2;
build(L(t), l, mid);
build(R(t), mid + 1, r);
node[t].maxx = max(node[L(t)].maxx, node[R(t)].maxx);
node[t].minx = min(node[L(t)].minx, node[R(t)].minx);
}
void query(int t, int l, int r) {
if (t > 200000) {
minx = maxx = 0;
return;
}
if (node[t].left == l&&node[t].right == r) {
if (maxx < node[t].maxx)
maxx = node[t].maxx;
if (minx > node[t].minx)
minx = node[t].minx;
return;
}
const int mid = (node[t].left + node[t].right) / 2;
if (l > mid) {
query(R(t), l, r);
}
else if (r <= mid) {
query(L(t), l, r);
}
else {
query(L(t), l, mid);
query(R(t), mid + 1, r);
}
}
int main()
{
//freopen("s.txt", "r", stdin);
int n, q, i;
scanf("%d%d", &n, &q);
for (i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
}
init();
build(1, 1, n);
while (q--) {
int a, b;
scanf("%d%d", &a, &b);
maxx = 0;
minx = INF;
query(1, a, b);
printf("%d\n", maxx - minx);
}
return 0;
}
手机扫一扫
移动阅读更方便
你可能感兴趣的文章