POJ 3264: Balanced Lineup

本文介绍使用线段树解决区间最大最小值查询问题的方法。通过构建线段树并进行查询操作,有效地解决了区间内元素的最大值与最小值之差的问题。

题目在此

解题思路:查询区间最大值/最小值之差,最基础的线段树应用。

代码:


#include <cstdio>

// 线段树为完全二叉树,因此可用 root * 2 和 root * 2 + 1
// 来求得左右孩子节点的位移
#define L(root) ((root) << 1)
#define R(root) (((root) << 1) + 1)
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))

const int MAXN = 50001;
int cows[MAXN];
int maxn, minn;

struct st {
	// 左右区间
    int left, right;
	// 区间最大、最小值
    int max, min;
} st[MAXN * 4];

// 建树
void build(int root, int l, int r) {
	// 区间为叶子节点时,初始化各值后返回
    st[root].left = l, st[root].right = r;
    if (l == r) {
        st[root].max = st[root].min = cows[l];
        return;
    }

	// 否则,递归构建左右节点
    int m = l + ((r - l) >> 1);
    build(L(root), l, m);
    build(R(root), m + 1, r);
    st[root].max = MAX(st[L(root)].max, st[R(root)].max);
    st[root].min = MIN(st[L(root)].min, st[R(root)].min);
}

// 查询
void query(int root, int l, int r) {
	// 查询范围与节点区间范围恰好重合
    if (st[root].left == l && st[root].right == r) {
        maxn = MAX(maxn, st[root].max);
        minn = MIN(minn, st[root].min);
        return;
    }

	// 否则,将区间一分为二
    int m = st[root].left + ((st[root].right - st[root].left) >> 1);
	// 查询范围“落”在左子节点区间
    if (r <= m) {
        query(L(root), l, r);
	// 查询范围“落”在右子节点区间
    } else if (l > m) {
        query(R(root), l, r);
	// 左右子节点区间各有一部分被查询范围覆盖:
	// 将查询范围一分为二,分别查询左右子节点
    } else {
        query(L(root), l, m);
        query(R(root), m + 1, r);
    }
}

int main() {
    int N, Q;
    while (scanf("%d%d", &N, &Q) != EOF) {
        for (int i = 1; i <= N; ++i) {
            scanf("%d", &cows[i]);
        }

        build(1, 1, N);
        int l, r;
        while (Q--) {
            scanf("%d%d", &l, &r);
            maxn = 0, minn = 0x7FFFFFFF;
            query(1, l, r);
            printf("%d\n", maxn - minn);
        }
    }

    return 0;
}

转载于:https://my.oschina.net/Alexanderzhou/blog/204056

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值