阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有N家住户,第i家住户到入口的距离为Si米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的X家住户推销产品,然后再原路走出去。阿明每走1米就会积累1点疲劳值,向第i家住户推销产品会积累Ai点疲劳值。阿明是工作狂,他想知道,对于不同的X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。
第一行有一个正整数N,表示螺丝街住户的数量。
接下来的一行有N个正整数,其中第i个整数Si表示第i家住户到入口的距离。数据保证S1≤S2≤…≤Sn<10^8。
接下来的一行有N个正整数,其中第i个整数Ai表示向第i户住户推销产品会积累的疲劳值。数据保证Ai<10^3。
输出N行,每行一个正整数,第i行整数表示当X=i时,阿明最多积累的疲劳值。
【样例1】
5
1 2 3 4 5
1 2 3 4 5
【样例2】
5
1 2 2 4 5
5 4 3 4 1
【样例1】
15
19
22
24
25
【样例2】
12
17
21
24
27
1≤N≤100000
注:请用 scanf 输入。
题解:线段树+贪心
维护两颗线段树,一棵维护区间单点权值的最大值及位置,另一棵维护s[i]*2+v[i]的最大值及位置。
x=1的时候答案肯定是第二棵线段树整个区间的最大值。
考虑x=i,答案一定是单调不降的。我们每次实际上是在x=i-1的基础上加入了一个点。之前入选的点一定会出现在当前的答案中。为什么呢?假设我们没有选择后面的点作为最远的点,那么说明前面存在一个点的疲劳值很大,足以大过后面的点比前面的点多出的距离。那么这样的点是一定后继续出现在后面的答案中的。我们一定求出了i-1的答案,有两种选择,一种是从当前点的前面选取没有选过的v[i]最大的点,最后入选的点不变;另一种是从当前最靠后的点的后面选取一点,相当于最靠后的点后移。计算出两种情况的答案,取较大的即可。注意选取过的点不能重复入选。
#include
#include
#include
#include
#include
#define N 400003
using namespace std;
int n,m;
int v[N],s[N],tr[N],tr1[N],pos[N],pos1[N],ans;
struct data
{
int x,y,pos,pos1;
};
void update(int now)
{
if (tr[now<<1]>tr[now<<1|1]) tr[now]=tr[now<<1],pos[now]=pos[now<<1];
else tr[now]=tr[now<<1|1],pos[now]=pos[now<<1|1];
if (tr1[now<<1]>tr1[now<<1|1]) tr1[now]=tr1[now<<1],pos1[now]=pos1[now<<1];
else tr1[now]=tr1[now<<1|1],pos1[now]=pos1[now<<1|1];
}
void build(int now,int l,int r)
{
if (l==r) {
tr[now]=v[l]; pos[now]=l;
tr1[now]=v[l]+s[l]*2; pos1[now]=r;
return;
}
int mid=(l+r)/2;
build(now<<1,l,mid);
build(now<<1|1,mid+1,r);
update(now);
}
void change(int now,int l,int r,int x)
{
if (l==r) {
tr[now]=0; tr1[now]=0;
return ;
}
int mid=(l+r)/2;
if (x<=mid) change(now<<1,l,mid,x);
else change(now<<1|1,mid+1,r,x);
update(now);
}
void cover(data &a,data b)
{
if (b.x>a.x) a.x=b.x,a.pos=b.pos;
if (b.y>a.y) a.y=b.y,a.pos1=b.pos1;
}
data qjask(int now,int l,int r,int ll,int rr)
{
if (ll>rr) {
data a; a.x=0; a.y=0;
return a;
}
if (ll<=l&&r<=rr) {
data a; a.x=tr[now]; a.y=tr1[now];
a.pos=pos[now]; a.pos1=pos1[now];
return a;
}
int mid=(l+r)/2;
data a; a.x=0; a.y=0;
if (ll<=mid) cover(a,qjask(now<<1,l,mid,ll,rr));
if (rr>mid) cover(a,qjask(now<<1|1,mid+1,r,ll,rr));
return a;
}
int main()
{
//freopen("a.in","r",stdin);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&s[i]);
for (int i=1;i<=n;i++) scanf("%d",&v[i]);
build(1,1,n);
printf("%d\n",tr1[1]); int k=pos1[1];
int ans=tr1[1];
data a; a=qjask(1,1,n,k,k);
int sum=a.x;
change(1,1,n,pos1[1]);
for (int i=2;i<=n;i++){
data a=qjask(1,1,n,1,k-1);
data b=qjask(1,1,n,k+1,n);
int t=a.x+ans;
int t1=sum+b.y;
if (t>t1) {
change(1,1,n,a.pos);
ans=t; sum+=a.x;
}
else {
k=b.pos1;
change(1,1,n,b.pos1);
ans=t1; sum+=b.x;
}
printf("%d\n",ans);
}
}