【codevs3304】水果姐逛水果店Ⅰ,线段树练习

水果姐逛水果街Ⅰ
时间限制: 2 s
空间限制: 256000 KB
题目等级 : 钻石 Diamond
题解
题目描述 Description
水果姐今天心情不错,来到了水果街。

水果街有n家水果店,呈直线结构,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样。

学过oi的水果姐迅速发现了一个赚钱的方法:在某家水果店买一个水果,再到另外一家店卖出去,赚差价。

就在水果姐窃喜的时候,cgh突然出现,他为了为难水果姐,给出m个问题,每个问题要求水果姐从第x家店出发到第y家店,途中只能选一家店买一个水果,然后选一家店(可以是同一家店,但不能往回走)卖出去,求每个问题中最多可以赚多少钱。

输入描述 Input Description
第一行n,表示有n家店

下来n个正整数,表示每家店一个苹果的价格。

下来一个整数m,表示下来有m个询问。

下来有m行,每行两个整数x和y,表示从第x家店出发到第y家店。

输出描述 Output Description
有m行。

每行对应一个询问,一个整数,表示面对cgh的每次询问,水果姐最多可以赚到多少钱。

样例输入 Sample Input
10
2 8 15 1 10 5 19 19 3 5
4
6 6
2 8
2 2
6 3

样例输出 Sample Output
0
18
0
14

数据范围及提示 Data Size & Hint
0<=苹果的价格<=10^8

n,m<=200000
写在前面:10个点跑了5s的煞笔代码
——————————————————————————————————————————————
思路:我会告诉你一上来我就看错题了吗?
调了半天才发现理解错题意了,不过改起来也不算太麻烦,主要就是对于一个区间内有序的最大差值的判断,就是max(左区间最大差值,右区间最大差值,左区间最大数值-右区间最小数值(或者右区间最大数值-左区间最小数值)),我的代码可能比较煞笔,大家凑活着看吧。
代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
    int maxn,minn,sum1,sum2;//sum1是指从左到右区间最大差值,sum2是从右到左区间最大差值
}tree[800010];
int n,q,head,tail;
int a[200010];
int in()
{
    int t=0;
    char ch=getchar();
    while (ch>'9'||ch<'0') ch=getchar();
    while (ch>='0'&&ch<='9') t=t*10+ch-'0',ch=getchar();
    return t;
}
void build_tree(int root,int begin,int end)
{
    if (begin==end) 
    {
        tree[root].maxn=tree[root].minn=a[end];
        return;
    }
    int mid=(begin+end)/2;
    build_tree(root*2,begin,mid);
    build_tree(root*2+1,mid+1,end);
    tree[root].maxn=max(tree[root*2].maxn,tree[root*2+1].maxn);
    tree[root].minn=min(tree[root*2].minn,tree[root*2+1].minn);
    tree[root].sum1=max(max(tree[root*2].sum1,tree[root*2+1].sum1),tree[root*2+1].maxn-tree[root*2].minn);
    tree[root].sum2=max(max(tree[root*2].sum2,tree[root*2+1].sum2),tree[root*2].maxn-tree[root*2+1].minn);
}
int findmin(int root,int begin,int end)
{
    if (begin>tail||end<head) return 23333333;
    if (begin>=head&&end<=tail) return tree[root].minn;
    int mid=(begin+end)/2,t=0X7fffffff;
    if (mid>=head) t=min(t,findmin(root*2,begin,mid));
    if (mid<tail) t=min(t,findmin(root*2+1,mid+1,end));
    return t;
}
int findmax(int root,int begin,int end)
{
    if (begin>tail||end<head) return -23333333;
    if (begin>=head&&end<=tail) return tree[root].maxn;
    int mid=(begin+end)/2,t=-0X7fffffff;
    if (mid>=head) t=max(t,findmax(root*2,begin,mid));
    if (mid<tail) t=max(t,findmax(root*2+1,mid+1,end));
    return t;
}
int find1(int root,int begin,int end)
{
    if (begin>tail||end<head) return -1;
    if (begin>=head&&end<=tail) return tree[root].sum1;
    int mid=(begin+end)/2,t=0;
    if (mid>=head) t=max(find1(root*2,begin,mid),t);
    if (mid<tail) t=max(find1(root*2+1,mid+1,end),t);
    t=max(findmax(root*2+1,mid+1,end)-findmin(root*2,begin,mid),t);
    return t;
}
int find2(int root,int begin,int end)
{
    if (begin>tail||end<head) return -1;
    if (begin>=head&&end<=tail) return tree[root].sum2;
    int mid=(begin+end)/2,t=0;
    if (mid>=head) t=max(find2(root*2,begin,mid),t);
    if (mid<tail) t=max(find2(root*2+1,mid+1,end),t);
    t=max(findmax(root*2,begin,mid)-findmin(root*2+1,mid+1,end),t);
    return t;
}
main()
{
    n=in();
    for (int i=1;i<=n;i++) a[i]=in();
    build_tree(1,1,n);
    q=in();
    for (int i=1;i<=q;i++)
    {
        head=in();
        tail=in();
        if (head>tail) swap(head,tail),printf("%d\n",find2(1,1,n)); 
        else printf("%d\n",find1(1,1,n));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值