题目描述
水果姐今天心情不错,来到了水果街。
水果街有n家水果店,呈直线结构,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样。
学过oi的水果姐迅速发现了一个赚钱的方法:在某家水果店买一个水果,再到另外一家店卖出去,赚差价。
就在水果姐窃喜的时候,cgh突然出现,他为了为难水果姐,给出m个问题,每个问题要求水果姐从第x家店出发到第y家店,途中只能选一家店买一个水果,然后选一家店(可以是同一家店,但不能往回走)卖出去,求每个问题中最多可以赚多少钱。
输入描述
第一行n,表示有n家店
下来n个正整数,表示每家店一个苹果的价格。
下来一个整数m,表示下来有m个询问。
下来有m行,每行两个整数x和y,表示从第x家店出发到第y家店。
输出描述
有m行。
每行对应一个询问,一个整数,表示面对cgh的每次询问,水果姐最多可以赚到多少钱。
样例输入
10
2 8 15 1 10 5 19 19 3 5
4
6 6
2 8
2 2
6 3
样例输出
0
18
0
14
数据范围及提示
0<=苹果的价格<=10^8
0<n,m<=200000
题解:线段树保存最大值、最小值、从左到右的最大差价、从右到左的最大差价。将两棵子树合并成一棵子树是这道题目的关键。通过使用update算出父节点的各个值,父节点的最大值即是子节点中的最大值,最小值即是子节点中的最小值,从左到右的最大差价即是左子树本来的从左到右的最大差价,右子树本来的从左到右的最大差价,右子树的最大值减去左子树的最小值这三者之间的最大值,从右到左的最大差价即是左子树本来的从右到左的最大差价,右子树本来的从右到左的最大差价,左子树的最大值减去右子树的最小值这三者之间的最大值,是op用来记录是要查询的是从左往右走,还是从右往左走,最后算出答案即可。
#include <cstdio>
#include <algorithm>
int n,m,x,y,op;
int a[200005];
struct tree{
int l,r,mx,mn,ls,rs;
}t[800005];
tree ans;
const int INF=1e9;
using namespace std;
inline int read()
{
int f=1,x=0;
char ch=getchar();
if (ch=='-')
{
f=-1;
ch=getchar();
}
while ((ch<'0')||(ch>'9')) ch=getchar();
while ((ch>='0')&&(ch<='9'))
{
x=x*10+ch-48;
ch=getchar();
}
return f*x;
}
tree update(tree x,tree y)
{
tree ans;
ans.l=x.l;
ans.r=y.r;
ans.mx=max(x.mx,y.mx);
ans.mn=min(x.mn,y.mn);
ans.ls=max(max(x.ls,y.ls),y.mx-x.mn);
ans.rs=max(max(x.rs,y.rs),x.mx-y.mn);
return ans;
}
inline void build(int root,int l,int r)
{
t[root].l=l,t[root].r=r;
if (l==r)
{
t[root].mx=t[root].mn=a[l];
return;
}
build(root<<1,l,(l+r)/2);
build(root<<1|1,(l+r)/2+1,r);
t[root]=update(t[root*2],t[root*2+1]);
}
inline void find(int root,int l,int r)
{
int ll=t[root].l,rr=t[root].r;
int mid=(ll+rr)/2;
if ((l<=ll)&&(rr<=r))
{
ans=update(ans,t[root]);
return;
}
if (l<=mid) find(root*2,l,r);
if (r>mid) find(root*2+1,l,r);
}
int main()
{
//freopen("1.in","r",stdin);
n=read();
for (int i=1;i<=n;i++) a[i]=read();
build(1,1,n);
m=read();
for (int i=1;i<=m;i++)
{
x=read(),y=read();
op=0;
if (x==y)
{
printf("0\n");
continue;
}
if (x>y)
{
swap(x,y);
op=1;
}
ans.mn=INF;
ans.mx=-INF;
ans.ls=ans.rs=0;
find(1,x,y);
if (op) printf("%d\n",ans.rs);
else printf("%d\n",ans.ls);
}
return 0;
}