POJ3264 Balanced Lineup(线段树模板题)

题目地址http://poj.org/problem?id=3264
题意
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.
给定Q (1 ≤ Q ≤ 50,000)个数A1,A2 … AQ,多次求任一区间中Ai – Aj中最大数和最小数的差。
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

AC代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>				//使用scanf进行输入,否则会TLE
#include<string>
#include<iostream>
#include<algorithm>
#include<map>
#include<set>
#include<stack>
#include<queue>
#include<vector>
#define ll long long
#define dd double
#define f(i, x, y) for(ll i = x; i < y; i++)
using namespace std;
ll minv = 10000000;
ll maxv = -10000000;

struct node {		//树结构,每一个tree[i]是一个节点,
					//每个节点有l(区间左端点)
					//         r(区间右端点)
					//         maxx(区间内数的最大值)
					//         minn(区间内数的最小值)、mid(区间中间点)
					//当l==r的时候,说明该节点是叶子节点
	ll l, r;
	ll maxx, minn;
	ll mid() {
		return (l + r) / 2;
	}
}tree[800010];

void BuildTree(ll root, ll l, ll r) {
//建树,此时数内什么都没有,是原始状态
	tree[root].l = l;
	tree[root].r = r;
	tree[root].maxx = -10000000;
	tree[root].minn = 10000000;
	if (l != r) {
		BuildTree(2 * root + 1, l, (l + r) / 2);
		BuildTree(2 * root + 2, (l + r) / 2 + 1, r);
	}
}

void Insert(ll root, ll i, ll v) {
//向树中插入数字,i代表位置,v代表数值
	if (tree[root].l == tree[root].r) {
	//当节点中区间左端点等于右端点的时候,是叶子节点,无法再向下分叉
	//此时,该区间内最大值和最小值等于v
		tree[root].maxx = v;
		tree[root].minn = v;
		return;
	}
	//如果不是叶子节点则在插入时更新该区间的最大值和最小值
	tree[root].maxx = max(tree[root].maxx, v);
	tree[root].minn = min(tree[root].minn, v);
	//如果该数字位置在左儿子那面就去左儿子继续插入,反之去右儿子
	if (i <= tree[root].mid()) {
		Insert(2 * root + 1, i, v);
	}
	else {
		Insert(2 * root + 2, i, v);
	}
}

void query(ll root, ll s, ll e) {
//查询树中的区间,s代表查找的区间左端点,e代表查找的区间右端点
	//剪枝,如果该区间内的最大值小于已经查询到的最大值且该区间最小值大于查询
	//到的最小值,则不必再向下查找
	if (tree[root].maxx <= maxv && tree[root].minn >= minv) {
		return;
	}
	//如果该区间正好是需要查找的区间,则更新最终结果并返回
	if (tree[root].l == s && tree[root].r == e) {
		maxv = max(tree[root].maxx, maxv);
		minv = min(tree[root].minn, minv);
		return;
	}
	//如果该区间在目前节点的左儿子内,则只查左儿子,
	//					 右儿子内,则只查右儿子,
	//否则两面同时查,并且更改查询区间
	if (e <= tree[root].mid()) {
		query(2 * root + 1, s, e);
	}
	else if (s > tree[root].mid()) {
		query(2 * root + 2, s, e);
	}
	else {
		query(2 * root + 1, s, tree[root].mid());
		query(2 * root + 2, tree[root].mid() + 1, e);
	}
}

int main() {
	ll n, m;
	scanf("%lld%lld",&n,&m);
	BuildTree(0, 1, n);
	f(i, 0, n) {
		ll q; scanf("%lld",&q);
		Insert(0, i + 1, q);
	}
	f(i, 0, m) {
	//每次查询前需要重新更新minv和maxv数值
		ll st; scanf("%lld",&st);
		ll en; scanf("%lld",&en);
		minv = 10000000;
		maxv = -10000000;
		query(0, st, en);
		printf("%lld\n",maxv-minv);
	}
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值