题目描述 Description
阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口的距离为Si米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的X家住户推销产品,然后再原路走出去。阿明每走1米就会积累1点疲劳值,向第i家住户推销产品会积累Ai点疲劳值。阿明是工作狂,他想知道,对于不同的X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。
输入描述 Input Description
第一行有一个正整数N,表示螺丝街住户的数量。
接下来的一行有N个正整数,其中第i个整数Si表示第i家住户到入口的距离。数据保证S1≤S2≤…≤Sn<10^8。
接下来的一行有N个正整数,其中第i个整数Ai表示向第i户住户推销产品会积累的疲劳值。数据保证Ai<10^3。
输出描述 Output Description
输出N行,每行一个正整数,第i行整数表示当X=i时,阿明最多积累的疲劳值。
样例输入 Sample Input
【样例1】
5
1 2 3 4 5
1 2 3 4 5
【样例2】
5
1 2 2 4 5
5 4 3 4 1
样例输出 Sample Output
【样例1】
15
19
22
24
25
【样例2】
12
17
21
24
27
数据范围及提示 Data Size & Hint
1≤N≤100000
注:请用 scanf 输入。
【题解】
根据线段树思想,先建立两棵线段树,一棵存距离*2+疲劳值,也就是s[i]*2+a[i],一棵存疲劳值,即a[i]。
建树之后,先特判第一个,也就是第一棵树上最大的值直接输出来,将位置存在mx中。
mx的作用是存每次处理之后已经取过的最远的点,也就是i最大的点。
之后根据mx,在mx的左边寻找疲劳值最大的点,记为a1。在mx的右边寻找s[i]*2+a[i]最大的点,记为a2。
因为a1是在mx的左边,所以如果取左边直接ans加上a1(最大疲劳值)就行了。但是因为a2在mx右边,所以如果取右边除了加上a2还要减去s[mx]*2,因为我们等于加了双重的s,即ans原=s[mx]*2+a[mx] , a2=max(s[i]*2+a[i])(mx<i<=n) , ans现=ans原+a2-s[mx]*2=s[mx]*2+a[mx]+max(s[i]*2+a[i])-s[mx]*2=a[mx]+max(s[i]*2+a[i])。
那么如何判断左边还是右边更优呢?
根据我们已经知道a1与a2在左/右边的区别,那么直接判断加完之后的数哪个大就好啦,即ans+a1 ?>(<) ans+a2-s[mx]*2。
然后如果取右边的点,则要更新mx。
还有一个点,就是mx-1<0,mx+1>n,a1=0,a2=0这几种情况要特别注意,写的时候记得加个特判。
说道更新mx,就要记录最大点的所在位置,只要每棵树开一个p数组存位置就好啦。
然后取过的点记得清零就好了。
代码
uses math; var n,i,j,ans,mx,a1,a2,pl1,pl2:longint; var a,sum,mn,p,sum1,mn1,p1,v,aa:array[0..400020] of longint; procedure up1(h:longint); begin sum[h]:=sum[h<<1]+sum[h<<1 or 1]; mn[h]:=max(mn[h<<1],mn[h<<1 or 1]); if mn[h<<1]>mn[h<<1 or 1] then p[h]:=p[h<<1] else p[h]:=p[h<<1 or 1]; end; procedure up2(h:longint); begin sum1[h]:=sum1[h<<1]+sum1[h<<1 or 1]; mn1[h]:=max(mn1[h<<1],mn1[h<<1 or 1]); if mn1[h<<1]>mn1[h<<1 or 1] then p1[h]:=p1[h<<1] else p1[h]:=p1[h<<1 or 1]; end; procedure build(h,l,r:longint); var m:longint; begin if l=r then begin sum[h]:=a[l];mn[h]:=a[l];p[h]:=l; sum1[h]:=aa[l];mn1[h]:=aa[l];p1[h]:=l;exit;end; m:=(l+r)>>1;build(h<<1,l,m);build(h<<1 or 1,m+1,r);up1(h);up2(h); end; procedure add1(h,c,l,r,x:longint); var m:longint; begin if (x<=l) and (x>=r) then begin inc(sum[h],c*(r-l+1));inc(mn[h],c);exit;end; m:=(l+r)>>1; if x<=m then add1(h<<1,c,l,m,x); if x>m then add1(h<<1 or 1,c,m+1,r,x); up1(h); end; procedure add2(h,c,l,r,x:longint); var m:longint; begin if (x<=l) and (x>=r) then begin inc(sum1[h],c*(r-l+1));inc(mn1[h],c);exit;end; m:=(l+r)>>1; if x<=m then add2(h<<1,c,l,m,x); if x>m then add2(h<<1 or 1,c,m+1,r,x); up2(h); end; function wm1(h,l,r,x,y:longint):longint; var m,ans,num:longint; begin if (x<=l) and (y>=r) then begin exit(mn[h]);end; m:=(l+r)>>1;ans:=-2147483647; if x<=m then begin num:=wm1(h<<1,l,m,x,y); if num>ans then begin ans:=num;pl1:=p[h<<1];end; end; if y>m then begin num:=wm1(h<<1 or 1,r+1,m,x,y); if num>ans then begin ans:=num;pl1:=p[h<<1 or 1];end; end; exit(ans); end; function wm2(h,l,r,x,y:longint):longint; var m,ans,num:longint; begin if (x<=l) and (y>=r) then begin exit(mn1[h]);end; m:=(l+r)>>1;ans:=-2147483647; if x<=m then begin num:=wm2(h<<1,l,m,x,y); if num>ans then begin ans:=num;pl2:=p1[h<<1];end; end; if y>m then begin num:=wm2(h<<1 or 1,r+1,m,x,y); if num>ans then begin ans:=num;pl2:=p1[h<<1 or 1];end; end; exit(ans); end; begin read(n);for i:=1 to n do read(v[i]); for i:=1 to n do begin read(aa[i]);a[i]:=v[i]*2+aa[i];end;build(1,1,n); writeln(a[p[1]]);mx:=p[1];ans:=a[p[1]]; add1(1,-a[mx],1,n,mx);add2(1,-aa[mx],1,n,mx); for i:=2 to n do begin a1:=wm2(1,1,n,1,mx-1); a2:=wm1(1,1,n,mx+1,n); if ((mx-1<0) or ((mx-1>0) and (mx+1<n) and (ans+a1>=ans+a2-v[mx]*2)) or (a1=0)) and (a2<>0) then begin inc(ans,a2-v[mx]*2);mx:=pl1;end else begin inc(ans,a1);pl1:=pl2;end; writeln(ans); add1(1,-a[pl1],1,n,pl1);add2(1,-aa[pl1],1,n,pl1); end; end.