好长时间不更新啦,急的FireStorm都来催稿了……
题目描述
水果姐今天心情不错,来到了水果街。
水果街有n家水果店,呈直线结构,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样。
学过oi的水果姐迅速发现了一个赚钱的方法:在某家水果店买一个水果,再到另外一家店卖出去,赚差价。
就在水果姐窃喜的时候,cgh突然出现,他为了为难水果姐,给出m个问题,每个问题要求水果姐从第x家店出发到第y家店,途中只能选一家店买一个水果,然后选一家店(可以是同一家店,但不能往回走)卖出去,求每个问题中最多可以赚多少钱。
另一个版本
一个人,在一个序列上走,单向,多次询问输出最大值减最小值……言简意赅
输入
第一行n,表示有n家店
下来n个正整数,表示每家店一个苹果的价格。
下来一个整数m,表示下来有m个询问。
下来有m行,每行两个整数x和y,表示从第x家店出发到第y家店。
输出
对于询问输出结果
样例
10
2 8 15 1 10 5 19 19 3 5
4
6 6
2 8
2 2
6 3
样例
0
18
0
14
范围
NlogN级别
分析
NlogN + 序列 + 多次询问
想到的一般是线段树……
那么问题来了
线段树,维护什么
首先可以确定的是,答案一定是某个最大值减去最小值(保证方向)
那么便用线段树去维护区间的最大值和最小值(ST?)
然后,正着走的ans和反着走的ans
足够了
答案由三部分构成(以从左往右走为例)
左边的ans
右边的ans
左边的max - 右边的minn
所以线段树就能维护了
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 2000000 + 5;
struct dot
{
int l,r;
int minn,maxn;
int ans1,ans2;
}tree[MAXN*4];
int num[MAXN];
void update(int x)
{
tree[x].maxn = max(tree[x << 1].maxn,tree[x << 1 | 1].maxn);
tree[x].minn = min(tree[x << 1].minn,tree[x << 1 | 1].minn);
tree[x].ans1 = max(tree[x << 1 | 1].maxn - tree[x << 1].minn,max(tree[x << 1].ans1,tree[x << 1 | 1].ans1));
tree[x].ans2 = max(tree[x << 1].maxn - tree[x << 1 | 1].minn,max(tree[x << 1].ans2,tree[x << 1 | 1].ans2));
return;
return;
}
void build(int p,int l,int r)
{
tree[p].l = l;
tree[p].r = r;
if(l == r)
{
tree[p].maxn = tree[p].minn = num[l];
tree[p].ans1 = tree[p].ans2 = 0;
return;
}
int mid = (l + r) >> 1;
build(p << 1,l,mid);
build(p << 1 | 1,mid + 1,r);
update(p);
return;
}
int minn(int p,int l,int r)
{
if(l <= tree[p].l && tree[p].r <= r)return tree[p].minn;
int mid = (tree[p].l + tree[p].r) >> 1;
int ans = 123456789;
if(l <= mid) ans = min(minn(p << 1,l,r),ans);
if(mid + 1 <= r) ans = min(minn(p << 1 | 1,l,r),ans);
return ans;
}
int maxn(int p,int l,int r)
{
if(l <= tree[p].l && r >= tree[p].r)return tree[p].maxn;
int mid = (tree[p].l + tree[p].r) >> 1;
int ans = 0;
if(l <= mid) ans = max(maxn(p << 1,l,r),ans);
if(mid + 1 <= r) ans = max(maxn(p << 1 | 1,l,r),ans);
return ans;
}
int z_ans(int p,int l,int r)
{
if(l <= tree[p].l && tree[p].r <= r)
return tree[p].ans1;
int ans = 0;
int mid = (tree[p].l + tree[p].r) >> 1;
if(l <= mid && mid + 1 <= r)
ans = max(ans,maxn(p << 1 | 1,mid + 1,r) - minn(p << 1,l,mid));
if(l <= mid)
ans = max(ans,z_ans(p << 1,l,r));
if(mid + 1 <= r)
ans = max(ans,z_ans(p << 1 | 1,l,r));
return ans;
}
int f_ans(int p,int l,int r)
{
if(l <= tree[p].l && tree[p].r <= r)
return tree[p].ans2;
int ans = 0;
int mid = (tree[p].l + tree[p].r) >> 1;
if(l <= mid && mid + 1 <= r)
ans = max(ans,maxn(p << 1,l,mid) - minn(p << 1 | 1,mid + 1,r));
if(l <= mid)
ans = max(ans,f_ans(p << 1,l,r));
if(mid + 1 <= r)
ans = max(ans,f_ans(p << 1 | 1,l,r));
return ans;
}
int n,m,l,r;
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;i ++)
scanf("%d",&num[i]);
build(1,1,n);
scanf("%d",&m);
for(int i = 1;i <= m;i ++)
{
scanf("%d %d",&l,&r);
if(l < r)
printf("%d\n",z_ans(1,l,r));
else
printf("%d\n",f_ans(1,r,l));
}
return 0;
}
就这样了……