[Codevs] 3304 水果姐逛水果街
3304 水果姐逛水果街Ⅰ
水果姐今天心情不错,来到了水果街。
水果街有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
分析 Analysis
偶遇菜菜qwq Orz CGH
这道题Tag线段树
心情极差直接思路
首先提出第一步思路:首先在建树的时候维护完整区间内的最优解
一般来说就是 Tree[rc].maxx - Tree[lc].minn (或者反过来)
然后根据题意我们知道 l 和 r 还可以翻来翻去的 --真好玩qwq-- 因为不可以Step Back所以需要保存两个顺序( --L->R / R->L--) 的最优解
(其实是根据WA知道的因为我第一次遇到这种情况直接强制 左端点 < 右端点 )
那么我们的线段树就有了如下元素:maxx minn ans1 ans2
其中maxx minn显然你们都懂的,ans1 保存从左到右时的最优解, ans2 保存从右到左时的最优解
接下来英勇地第二次WA
(按我这样初赛能过就不错了qwq)
仔细思考题意。
定义 [ ] 为操作区间,( ) 为查询区间,
当 ( [ ] ) 时,
答案 = max( Tree[当前结点].ans , Tree[右子树].maxx-Tree[左子树].minn )
当 [ ( ) ] 时,
答案 = max( 右子树中最大值-左子树中最小值 , 左子树中最优解 , 右子树中最优解 )
注意,第二种情况中没有用 Tree[ ]
惟一一个关键点就在这
根据我的理解,第二种情况中的左右子树,并不是一个完整区间,而是被一分为二的询问的不完整的区间。
因此这次query函数并不单纯返回一个值,而是返回一段不完整区间,这段不完整区间囊括了该区间内整个的信息。
一遍AC = =
代码 Code
1 #include<cstdio> 2 #include<iostream> 3 #define mid (L+R)/2 4 #define lc (rt<<1) 5 #define rc (rt<<1|1) 6 #define maxn 100000 7 using namespace std; 8 9 int n,m,a,b; 10 const int inf = 0x3f3f3f3f; 11 12 struct node{ 13 int maxx,minn,ans1,ans2; 14 node(){ 15 maxx = ans1 = ans2 = 0; 16 minn = inf; 17 } 18 19 // node(int a,int b,int c,int d){ 20 // maxx = a,minn = b,ans1 = c,ans3 = d; 21 // } 22 }Tree[maxn*100]; 23 24 void maintain(int rt){ 25 Tree[rt].maxx = max(Tree[lc].maxx,Tree[rc].maxx); 26 Tree[rt].minn = min(Tree[lc].minn,Tree[rc].minn); 27 Tree[rt].ans1 = max( Tree[rc].maxx-Tree[lc].minn , max(Tree[lc].ans1,Tree[rc].ans1) ); 28 Tree[rt].ans2 = max( Tree[lc].maxx-Tree[rc].minn , max(Tree[lc].ans2,Tree[rc].ans2) ); 29 } 30 31 void build(int rt,int L,int R){ 32 if(L == R){ 33 scanf("%d",&Tree[rt].maxx); 34 Tree[rt].minn = Tree[rt].maxx; 35 Tree[rt].ans1 = Tree[rt].ans2 = 0; 36 }else{ 37 build(lc,L,mid); 38 build(rc,mid+1,R); 39 40 maintain(rt); 41 } 42 } 43 44 node query(int rt,int L,int R,int qL,int qR){ 45 if(qL <= L && R <= qR){ 46 return Tree[rt]; 47 }else{ 48 node cnt; 49 50 node LC,RC; 51 if(qL <= mid) LC = query(lc,L,mid,qL,qR); 52 // else LC = (node){0,inf,0,0}; 53 54 if(qR > mid) RC = query(rc,mid+1,R,qL,qR); 55 // else RC = (node){0,inf,0,0}; 56 57 cnt.maxx = max(LC.maxx,RC.maxx); 58 cnt.minn = min(LC.minn,RC.minn); 59 cnt.ans1 = max(max(LC.ans1,RC.ans1),RC.maxx-LC.minn); 60 cnt.ans2 = max(max(LC.ans2,RC.ans2),LC.maxx-RC.minn); 61 62 return cnt; 63 } 64 } 65 66 int main(){ 67 scanf("%d",&n); 68 69 build(1,1,n); 70 71 scanf("%d",&m); 72 73 for(int i = 1;i <= m;i++){ 74 scanf("%d%d",&a,&b); 75 76 if(a < b){ 77 node ans = query(1,1,n,a,b); 78 printf("%d\n",ans.ans1); 79 }else{ 80 node ans = query(1,1,n,b,a); 81 printf("%d\n",ans.ans2); 82 } 83 } 84 85 86 return 0; 87 }