题目描述
水果姐今天心情不错,来到了水果街。
水果街有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; }