AOJ-AHU-OJ-351 求最值之差

求最值之差
Time Limit: 1000 ms   Case Time Limit: 1000 ms   Memory Limit: 64 MB
Description
给出N个数,求第a个数到第b个数之间最大的数减去最小的数的结果

Input
N(N小于100,000),M(M小于100,000)
接下来有N个数
接下来M组范围,所有数均在[0,2 31-1]内
每个范围有2个整数a,b(1<=a<=b<=N)


Output
每行输出一个结果

Sample Input
OriginalTransformed
5 3
4 2 5 1 10
1 5
2 3
2 2

Sample Output
OriginalTransformed
9
3
0

————————————————————开森的分割线————————————————————

思路:学了NotOnlySuccess的HDU上的敌兵布阵的线段树之后,拿这道题目练一练手。毕竟线段树时间复杂度是O(logN)嘛!此题不一样的地方就在于不求和,求差。而且多了一样东西“最值”。灰常容易想到的方法,就是建立两棵树,一棵存最大值,另一棵存最小值。需要的时候,查询并且返回需要的最值,作差即可。注意!运用带参数的宏定义的时候,小心不要进行重复运算。否则一不小心就把你的复杂度乘以2了。

代码如下:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#define N 100010
#define lson l, m, id << 1
#define rson m+1, r, id << 1 | 1
#define maxi(a, b) (a > b ? a : b)
#define mini(a, b) (a < b ? a : b)
int Max[N<<2], Min[N<<2];
void FindM(int id) {//构建最值树
    Max[id] = maxi(Max[id<<1], Max[id<<1|1]);
    Min[id] = mini(Min[id<<1], Min[id<<1|1]);
}
void build(int l, int r, int id) {
    if(l == r) {
        scanf("%d", Max+id);
        Min[id] = Max[id];
        return ;
    }
    int m = (l+r) >> 1;
    build(lson); build(rson);//左右开弓
    FindM(id);
}
int Q1(int L, int R, int l, int r, int id) {//询问函数1,询问最大值
    if(L <= l&&r <= R)
        return Max[id];
    int m = (l+r) >> 1;
    int ans = 0;
    if (L <= m) {
        int u1 = Q1(L, R, lson);
        ans = maxi(ans, u1);//注意,借助新变量使用宏定义,避免复杂度×2
    }
    if (R > m) {
        int u2 = Q1(L, R, rson);
        ans = maxi(ans, u2);
    }
    return ans;//最终return的一定是它
}
int Q2(int L, int R, int l, int r, int id) {
    if(L <= l&&r <= R)
        return Min[id];
    int m = (l+r) >> 1;
    int res = 2147483647;
    if (L <= m) {
        int u1 = Q2(L, R, lson);
        res = mini(res, u1);
    }
    if (R > m) {
        int u2 = Q2(L, R, rson);
        res = mini(res, u2);
    }
    return res;
}
int main() {
	int len, cas;
	scanf("%d%d", &len, &cas);
	build(1, len, 1);
    /*for(int i = 1; i <= len << 2; i++)
        printf("%d ", Max[i]);
    puts("");
    for(int i = 1; i <= len << 2; i++)
        printf("%d ", Min[i]);
        */
    while(cas--) {
        int A, B;
        scanf("%d%d", &A, &B);
        if(A == B)
        printf("0\n");
        else
        printf("%d\n", Q1(A, B, 1, len, 1) - Q2(A, B, 1, len, 1));
    }
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值