Supermarket POJ - 1456

题目链接

题目大意:
给你n个商品:
每个商品有两个属性:
1,价值;2,最晚销售天数
且:每一天只可以买一件商品
求:可以获得的最大价值;
题目分析:
可以把这道题理解成了一道贪心的题目;
从这些商品里获得最大的价值;
既然是贪心,那么我的决策是什么:
尽量把价格高的卖出去
问题来了,在什么时候卖这些商品呢?
假如商品时间为n,那么销售的时间的区间是【1,n】,
最优的时间是什么呢?
当然是当天销售,这样对于同一天的商品来说,对价格排序后,肯定是价格高的先卖完。
当是如果这一天被占用了呢?
可以在【1,n-1】天里,找到一个距离n天最近的没有被占的时间,去销售;
那为什么不从前往后找呢?在第i天找,影响的是在【i,max】天销售的商品,i越大,影响的越小;

//暴力寻找[1,d-1]天内没被占用的天数;
还可以线段树查询;
//线段树维护距离n点最近的一个没被占的点的信息;

#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int num=20012;
struct node
{
     
    int d,v;
}a[num];
bool vis[num];
bool cmp(node c,node b)
{
     
    return c.v > b.v;
}
//维护的是一棵树,k记录的这个区间最右边的非0的位置;
struct point
{
     
    int L,R,s;
}e[num<<2];
void update(int k)
{
     
    e[k].s=max(e[k<<1].s,e[k<<1|1].s);
    return ;
}
void build(int k,int L,int R)
{
     
    e[k].L=L;e[k].R=R;
    if(L==R) {
     
        e[k].s=R;
        return ;
    }

    int mid=(e[k].L+e[k].R)>>1;
    build(k<<1,L,mid);
    build(k<<1|1,mid+1,R);
    update(k);
    return;
}
void change(int k,int L,int R)
{
     
    if(e[k].R==R&&e[k].L==L)
    {
     
        e[k].s=0;
        return ;
    }
    int mid=(e[k].L+e[k].R)>>1;
    if(L<=mid) change(k<<1,L,R);
    if(R>mid)  change(k<<1|1,L,R);
    update(k);
    return ;
}
int search(int k,int L,int R)
{
     
    if(e[k].L>=L&&e[k].R<=R)
    {
     
        return e[k].s;
    }
    int mid=(e[k].L+e[k].R)>>1;
    int ans=0;
    if(L<=mid) ans=max(search(k<<1,L,R),ans);
    if(R>mid)  ans=max(search(k<<1|1,L,R),ans);
    return ans;
}
int main()
{
     
    int n;
    while(scanf("%d",&n)!=EOF)
    {
     
        if(n==0){
     
            printf("0\n");
            continue;
        }

        memset(vis,0,sizeof(vis));
        int mx=0;
        for(int i=1;i<=n;i++)
        {
     
            scanf("%d%d",&a[i].v,&a[i].d);
            mx=max(mx,a[i].d);
        }

        sort(a+1,a+n+1,cmp);

        int ans=0;
        build(1,1,mx);

        for(int i=1;i<=n;i++)
        {
     
            if(!vis[a[i].d]){
     
                vis[a[i].d]=1;
                change(1,a[i].d,a[i].d);
                ans+=a[i].v;
            }
            else
            {
     
                if(a[i].d==1) continue;//[1,n]是按照价格的大小排序的 
                int pos=search(1,1,a[i].d);
                if(pos>0)
                {
     
                    change(1,pos,pos);
                    vis[pos]=1;
                    ans+=a[i].v;
                }

/*
                for(int j=a[i].d-1;j>=1;j--)
                {
                    if(!vis[j])
                    {
                        vis[j]=1;
                        ans+=a[i].v;
                        break;
                    }
                }
 */

            }

    	}
        printf("%d\n",ans);
    }
    return 0;
}


你可能感兴趣的:(线段树,贪心,贪心,线段树维护)