1. 程式人生 > 實用技巧 >【線段樹】買水果

【線段樹】買水果

Description

  水果姐今天心情不錯,來到了水果街。
  水果街有n家水果店,呈直線結構,編號為1~n,每家店能買水果也能賣水果,並且同一家店賣與買的價格一樣。
  學過oi的水果姐迅速發現了一個賺錢的方法:在某家水果店買一個水果,再到另外一家店賣出去,賺差價。
  就在水果姐竊喜的時候,cgh突然出現,他為了為難水果姐,給出m個問題,每個問題要求水果姐從第x家店出發到第y家店,途中只能選一家店買一個水果,然後選一家店(可以是同一家店,但不能往回走)賣出去,求每個問題中最多可以賺多少錢。

Input

  第一行n,表示有n家店
  下來n個正整數,表示每家店一個蘋果的價格。
  下來一個整數m,表示下來有m個詢問。
  下來有m行,每行兩個整數x和y,表示從第x家店出發到第y家店。

Output

  有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

Hint

  0<=蘋果的價格<=10^8
  1<=n,m<=200000


思路

  • 線段樹記錄:最大值,最小值,從左往右的答案,從右往左的答案(兩個買賣水果點在兩個不同區間/相同區間,有點像旅館Hotel(USACO 2008 February Gold))
  • 有可能從右往左走,所以answer=max{右區間的最大值-左區間的最小值/左區間的最大值-右區間的最小值,左區間的答案,右區間的答案}

程式碼

#include <iostream>
#include <cstdio>
#define maxn 200005
using namespace std;
int n,m,v[maxn];
struct fdfdfd{int l,r,maxx,minn,ans1,ans2;}a[maxn<<2];
void pushup(int x)
{
	a[x].maxx=max(a[x<<1].maxx,a[x<<1|1].maxx);
	a[x].minn=min(a[x<<1].minn,a[x<<1|1].minn);
	a[x].ans1=max(a[x<<1|1].maxx-a[x<<1].minn,max(a[x<<1].ans1,a[x<<1|1].ans1));
	a[x].ans2=max(a[x<<1].maxx-a[x<<1|1].minn,max(a[x<<1].ans2,a[x<<1|1].ans2));
}
void build(int x,int left,int right)
{
	a[x].l=left; a[x].r=right;
	if(left==right){a[x].maxx=a[x].minn=v[left]; return;}
	int mid=(left+right)>>1;
	build(x<<1,left,mid); build(x<<1|1,mid+1,right);
	pushup(x);
}
fdfdfd query(int x,int left,int right)
{
	if(a[x].l>right||a[x].r<left) return (fdfdfd){0,0,-1,0x7fffffff,-1,-1};
	if(left<=a[x].l&&right>=a[x].r) return a[x];
	fdfdfd temp1=query(x<<1,left,right),temp2=query(x<<1|1,left,right),temp;
	temp.ans1=max(max(temp1.ans1,temp2.ans1),temp2.maxx-temp1.minn);
	temp.ans2=max(max(temp1.ans2,temp2.ans2),temp1.maxx-temp2.minn);
	temp.minn=min(temp1.minn,temp2.minn);
	temp.maxx=max(temp1.maxx,temp2.maxx);
	return temp;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&v[i]);
	build(1,1,n); scanf("%d",&m);
	while(m--)
	{
		int f1,f2; scanf("%d%d",&f1,&f2);
		if(f1==f2) puts("0");
		else if(f1<f2) printf("%d\n",query(1,f1,f2).ans1);
		else printf("%d\n",query(1,f2,f1).ans2);
	}
	return 0;
}