洛谷P2672 NOIP2015普及组第四题

题目描述

      阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有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 
#include 
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

===========================================================================

//线段树
#include 
#include 
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;
}


你可能感兴趣的:(NOIP2015普及组,贪心,线段树)