code vs 5126 推销员 NOIP2015 (线段树+贪心)
2016-10-28 08:02
471 查看
5126 推销员 NOIP2015
时间限制: 1 s空间限制: 128000 KB
题目等级 : 黄金 Gold
题解
查看运行结果
题目描述 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 输入。
题解:线段树+贪心
维护两颗线段树,一棵维护区间单点权值的最大值及位置,另一棵维护s[i]*2+v[i]的最大值及位置。
x=1的时候答案肯定是第二棵线段树整个区间的最大值。
考虑x=i,答案一定是单调不降的。我们每次实际上是在x=i-1的基础上加入了一个点。之前入选的点一定会出现在当前的答案中。为什么呢?假设我们没有选择后面的点作为最远的点,那么说明前面存在一个点的疲劳值很大,足以大过后面的点比前面的点多出的距离。那么这样的点是一定后继续出现在后面的答案中的。我们一定求出了i-1的答案,有两种选择,一种是从当前点的前面选取没有选过的v[i]最大的点,最后入选的点不变;另一种是从当前最靠后的点的后面选取一点,相当于最靠后的点后移。计算出两种情况的答案,取较大的即可。注意选取过的点不能重复入选。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#define N 400003
using namespace std;
int n,m;
int v
,s
,tr
,tr1
,pos
,pos1
,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);
}
}
相关文章推荐
- 【codevs 5126】[NOIP2015 普及组T4]推销员(贪心)
- luogu2672推销员-贪心-(noip2015普及t4)
- [普及]NOIP 2015 推销员
- hdu 5338 ZZX and Permutations 2015多校联合训练赛,贪心,线段树,树状数组
- 【BZOJ4325】NOIP2015 斗地主 搜索+贪心
- 【NOIP 2015】斗地主 贪心+迭代加深搜索
- NOIP 2015 推销员
- UOJ147 [NOIP2015]斗地主 解题报告【搜索】【贪心】
- [noip2015]斗地主(dfs+贪心)
- [jzoj]4216. 【NOIP2015模拟9.12】平方和【线段树二分+码量】
- [NOIP2015]推销员
- [NOIp2015普及组]推销员
- NOIP2015斗地主[DFS 贪心]
- 【JZOJ 4310】【NOIP2015模拟11.4】最优交换(贪心)
- |洛谷|NOIP2015|堆|P2672 推销员
- [NOIP模拟题][Catalan数][逆元][贪心][线段树][DFS][搜索顺序剪枝]
- 【NOIP2015普及组T4】推销员-优先队列
- UOJ 147|NOIP 2015|斗地主|搜索|贪心
- [NOIP2015][Vijos1977]推销员(heap)
- NOIP2015 推销员