水果姐今天心情不错,来到了水果街。
水果街有n家水果店,呈直线结构,编号为1~n,每家店能买水果也能卖水果,并且同一家店卖与买的价格一样。
学过oi的水果姐迅速发现了一个赚钱的方法:在某家水果店买一个水果,再到另外一家店卖出去,赚差价。
就在水果姐窃喜的时候,cgh突然出现,他为了为难水果姐,给出m个问题,每个问题要求水果姐从第x家店出发到第y家店,途中只能选一家店买一个水果,然后选一家店(可以是同一家店,但不能往回走)卖出去,求每个问题中最多可以赚多少钱。
思路:水果姐系列的线性问题,用线段树维护,节省时间。用结构体中的四项(区间最大、小值,区间最大贸易值(正、反))。这里有一个很巧妙的东西,就是对于区间[a,b],它的最大、小值比较简单,但是最大贸易值由左右孩子区间的最大贸易值和左右区间的最大最小值的差值得到,进行更新。一开始用了四个数组,后来发现tle,于是就借鉴了dada的程序,改成了结构体,结果又犯了个神奇的错误(直接将tree的值更改了),只需返回值就可以了。。。
#include<iostream> #include<cstdio> using namespace std; struct use{ int maxi,mini,zan,fan; }tr[800000]; int a[200001]={0},n; void build(int i,int l,int r) { int mid; if (l==r) { tr[i].maxi=tr[i].mini=a[l]; return; } mid=(l+r)/2; build(i*2,l,mid); build(i*2+1,mid+1,r); tr[i].maxi=max(tr[i*2].maxi,tr[i*2+1].maxi); tr[i].mini=min(tr[i*2].mini,tr[i*2+1].mini); tr[i].zan=max(tr[i*2].zan,max(tr[i*2+1].zan,tr[i*2+1].maxi-tr[i*2].mini)); tr[i].fan=max(tr[i*2].fan,max(tr[i*2+1].fan,tr[i*2].maxi-tr[i*2+1].mini)); } struct use work(int i,int l,int r,int x,int y) { int mid,maxn=0; struct use tem,temm,temi; if (x>r||y<l) return (use){-1,2100000000,-1,-1}; if (x<=l&&r<=y) return tr[i]; mid=(l+r)/2; tem=work(i*2,l,mid,x,y); temm=work(i*2+1,mid+1,r,x,y); temi.maxi=max(tem.maxi,temm.maxi); temi.mini=min(tem.mini,temm.mini); temi.zan=max(tem.zan,max(temm.zan,temm.maxi-tem.mini)); temi.fan=max(tem.fan,max(temm.fan,tem.maxi-temm.mini)); return temi; } int main() { int m,i,j,x,y; struct use ans; scanf("%d",&n); for (i=1;i<=n;++i) scanf("%d",&a[i]); build(1,1,n); scanf("%d",&m); for (i=1;i<=m;++i) { scanf("%d%d",&x,&y); if (x==y) printf("0\n"); else { if (x<y) { ans=work(1,1,n,x,y); printf("%d\n",ans.zan); } else { ans=work(1,1,n,y,x); printf("%d\n",ans.fan); } } } }