题目描述
阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有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
输出样例#1:
15
19
22
24
25
输入样例#2:
5
1 2 2 4 5
5 4 3 4 1
输出样例#2:
12
17
21
24
27
解题思路:
这道题目可以有两种做法,一种是贪心,一种是线段树。
贪心如何去做呢?首先,要按照每户的疲劳度去从大到小排序,然后,逐个去搜索,即可得到答案。
线段树的话~~~这种模板,应该就用不着解释了吧~~~
代码:(请不要直接拷贝哦)
//贪心
#include <cstdio>
#include <algorithm>
struct pl{
int s,val;
}a[100005];
int maxx,j,k,ans;
using namespace std;
bool cmp(pl x,pl y)
{
return x.val>y.val;//按照向每家推销的疲劳度排序
}
int main()
{
int n;
//freopen("1.in","r",stdin);
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i].s);
for (int i=1;i<=n;i++) scanf("%d",&a[i].val);
sort(a+1,a+n+1,cmp);
for (int i=1;i<=n;i++)
if (2*a[i].s+a[i].val>maxx)//当当前这户人家来回的疲劳度+推销的疲劳度最大时,这就是我们需要找到的第一个答案
{
maxx=2*a[i].s+a[i].val;//记录下来
j=k=i;//记住这个点,下次搜寻时这个点不要再算了,否则会WA的
}
ans+=maxx;
printf("%d\n",ans);
for (int i=1;i<=n;i++)
{
if (i==k) continue;//搜寻过了,直接跳过
if (a[j].s<a[i].s)
{
ans=ans-2*a[j].s+2*a[i].s+a[i].val;//重新计算答案
j=i;
printf("%d\n",ans);
} else
{
ans+=a[i].val;
printf("%d\n",ans);
}
}
return 0;
}
===========================================================================
//线段树
#include <cstdio>
#include <algorithm>
struct TREE{
int l,r,mid,lazy,number,val;
}tree[400005];
int s[100005],a[100005];
int ans,now,last;
using namespace std;
inline void push_up(int x)
{
if (tree[x*2].val>=tree[x*2+1].val)
{
tree[x].number=tree[x*2].number;
tree[x].val=tree[x*2].val;
} else
{
tree[x].number=tree[x*2+1].number;
tree[x].val=tree[x*2+1].val;
}
}
inline void push_down(int x)
{
tree[x*2].val+=tree[x].lazy;
tree[x*2+1].val+=tree[x].lazy;
tree[x*2].lazy+=tree[x].lazy;
tree[x*2+1].lazy+=tree[x].lazy;
tree[x].lazy=0;
}
inline void build(int x,int l,int r)
{
tree[x].l=l,tree[x].r=r,tree[x].mid=(l+r)/2;
if (l==r)
{
tree[x].number=l;
tree[x].val=s[l]*2+a[l];
return;
}
build(x*2,l,tree[x].mid);
build(x*2+1,tree[x].mid+1,r);
push_up(x);
}
inline void change(int x)
{
if (tree[x].r<=last) return;
if (tree[x].l>now)
{
tree[x].val-=(s[now]-s[last])*2;
tree[x].lazy-=(s[now]-s[last])*2;
return;
}
if (tree[x].l==tree[x].r)
{
tree[x].val=a[tree[x].l];
return;
}
if (tree[x].lazy) push_down(x);
change(x*2);
change(x*2+1);
push_up(x);
}
inline void xg(int x)
{
if (tree[x].l==tree[x].r)
{
tree[x].val=-600000000;
return;
}
if (now<=tree[x].mid) xg(x*2);
else xg(x*2+1);
push_up(x);
}
int main()
{
int n;
//freopen("1.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",&a[i]);
build(1,1,n);//建树
for (int i=1;i<=n;i++)
{
ans+=tree[1].val;//算答案,第一个即为我们想要的值
now=tree[1].number;
printf("%d\n",ans);
if (now>last)
{
change(1);//改变树
last=now;//更新last
}
xg(1);//将now删除掉
}
return 0;
}