题目描述 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.
浙公网安备 33010602011771号