Codevs3304水果姐逛水果街Ⅰ题解

http://codevs.cn/problem/3304/

  • 题解
    本题是一道明显的区间查询问题,可以很快想到线段树之类的数据结构。(不知为什么分到了区间dp里,预处理至少 On2 ,dp真的能过吗?)

  • 首先是建树。由题意,显然每个结点都应包括区间左端点右端点最大值最小值,由于要走单向的路线,所以还应该有区间从左到右走的最大差值从右到左走的最大差值。其中max和min的值很容易维护,那么剩下的就是两个最大差值了。

  • 先考虑叶子结点,那这两个方向的最大差值显然都是0;
    线段树的核心是合并两个区间,那已知两个子区间,如何把最大差值和并呢?
    从左到右走的最大差值为例,这要分三种情况:
    1、差值在左子树的区间取得,而左子树的所有情况都是知道的;
    2、差值在右子树的区间取得,而右子树的所有情况都是知道的;
    3、差值为右子树的最大值减去左子树的最大值,而左子树和右子树的所有情况都是知道的;
    这三种情况取最大即可。
    从右到左走的最大差值同理,只需要把第3种情况改成左子树的最大值减去右子树的最小值即可。

  • 树建好了,那本题也就基本解决了。
    对于 x==y 的情况,答案一定是0,直接输出吧,省时间。
    对于这一段查询区间 [x,y] ,从根开始找,若线段树结点对应的区间被查询区间所包含,直接返回答案;若不涉及右子树,则只查询左子树;若不涉及左子树,则只查询右子树:这是线段树的基本查询方式了。
    左右子树同时涉及时,只需要在左子树和右子树中分别查询最大差值和最值,答案就是最大差值的最大值和最值差之间的最大值。

  • Code

#include <cstdio>
#include <algorithm>
#define tlc(k) (k << 1)
#define trc(k) (k << 1 | 1)
using namespace std;
const int maxn = 800100, root = 1, nil = 0;
int tmax[maxn], tmin[maxn], ansl[maxn], ansr[maxn], lc[maxn], rc[maxn];
int n, m, a[maxn >> 2];
void update(int k)
{
    tmax[k] = max(tmax[tlc(k)], tmax[trc(k)]);
    tmin[k] = min(tmin[tlc(k)], tmin[trc(k)]);
    ansl[k] = max(ansl[tlc(k)], ansl[trc(k)]);
    ansl[k] = max(ansl[k], tmax[trc(k)] - tmin[tlc(k)]);
    ansr[k] = max(ansr[tlc(k)], ansr[trc(k)]);
    ansr[k] = max(ansr[k], tmax[tlc(k)] - tmin[trc(k)]);
}
void build(int rot, int l, int r)
{
    if(l == r)
    {
        tmax[rot] = tmin[rot] = a[l];
        ansl[rot] = ansr[rot] = 0;
        lc[rot] = rc[rot] = l;
        return;
    }
    int mid = ((l + r) >> 1);
    lc[rot] = l; rc[rot] = r;
    build(tlc(rot), l, mid);
    build(trc(rot), mid + 1, r);
    update(rot);
}
int querymax(int rot, int l, int r)
{
    if(l <= lc[rot] && r >= rc[rot]) return tmax[rot];
    int mid = ((lc[rot] + rc[rot]) >> 1);
    if(r <= mid) return querymax(tlc(rot), l, r);
    else if(l > mid) return querymax(trc(rot), l, r);
    else return max(querymax(tlc(rot), l, r), querymax(trc(rot), l, r));
}
int querymin(int rot, int l, int r)
{
    if(l <= lc[rot] && r >= rc[rot]) return tmin[rot];
    int mid = ((lc[rot] + rc[rot]) >> 1);
    if(r <= mid) return querymin(tlc(rot), l, r);
    else if(l > mid) return querymin(trc(rot), l, r);
    else return min(querymin(tlc(rot), l, r), querymin(trc(rot), l, r));
}
int queryl(int rot, int l, int r)
{
    if(l <= lc[rot] && r >= rc[rot]) return ansl[rot];
    int mid = ((lc[rot] + rc[rot]) >> 1);
    if(r <= mid) return queryl(tlc(rot), l, r);
    else if(l > mid) return queryl(trc(rot), l, r);
    else
    {
        int tmp = max(queryl(tlc(rot), l, mid), queryl(trc(rot), mid + 1, r));
        tmp = max(tmp, querymax(trc(rot), mid + 1, r) - querymin(tlc(rot), l, mid));
        return tmp;
    }   
}
int queryr(int rot, int l, int r)
{
    if(l <= lc[rot] && r >= rc[rot]) return ansr[rot];
    int mid = ((lc[rot] + rc[rot]) >> 1);
    if(r <= mid) return queryr(tlc(rot), l, r);
    else if(l > mid) return queryr(trc(rot), l, r);
    else
    {
        int tmp = max(queryr(tlc(rot), l, mid), queryr(trc(rot), mid + 1, r));
        tmp = max(tmp, querymax(tlc(rot), l, mid) - querymin(trc(rot), mid + 1, r));
        return tmp;
    }   
}
void init()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    build(root, 1, n);
    scanf("%d", &m);
}
void work()
{
    int x, y;
    while(m--)
    {
        scanf("%d%d", &x, &y);
        if(x < y) printf("%d\n", queryl(root, x, y));
        else if(x > y) printf("%d\n", queryr(root, y, x));
        else puts("0");
    }
}
int main()
{
    init();
    work();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值