dtoi4641 小店购物

题意:

     有n个商品,每个商品有一个价格和价值。m次操作,每次更改一个商品的信息或者询问一个k,表示一开始有k元钱,然后问会买到价值多少的商品。

     购买方式很特别,分若干轮,每一轮从我能买的物品中选择一个价值最大的(相同的选择价格最小的),然后买下它,重复上述操作,直到买不了任何东西。

     n,m<=100000,其余数值<=1000000000。

题解:

     如果每次只买一轮,那么问题很简单,使用权值线段树维护商品价值最大值即可。

     那么如果要买很多轮,那对于每一轮,会买到一个商品,这个商品是能买到的价值最大的。

     这意味着什么,意味着下一轮如果有能力购买它,依然会选择它。也就是说,找到一个要买的物品,然后一直买直到钱不够买它为止(这个价值可以直接计算),再进行下一轮购买。

     这样的效率就是m*log*操作的轮数。可以证明,按照这样的方法操作,操作次数不会超过log2(1000000000)。

     证明也很容易,如果这个商品的价格>手里钱数的一半,那减掉他之后钱数至少减半。如果商品价格<手里钱数的一半,那会一直买它直到买不起,那么最后钱数也会<商品价格<原来钱数的一半。所以每次钱数至少减半,那么操作次数就是log次。

     还有个修改操作,由于物品的价格可能会相同,所以在线段树的每一个叶子上面要开一个multiset来记录商品,用于增加和删除。

扫描二维码关注公众号,回复: 9033944 查看本文章
#include<cstdio>
#include<set>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int INF=1e9;
int n,m,w[100002],p[100002],cnt=1,Max,cost;
multiset<int>q[6000002];
typedef struct{
    int ls,rs,Max,cost;
}XDS;
XDS xds[6000002];
void gengxin(int root,int begin,int end,int wz,int z,bool u){
    if (begin==end)
    {
        if (u)
        {
            q[root].insert(z);multiset<int>::iterator it=q[root].end();it--;
            xds[root].Max=*it;xds[root].cost=begin;
        }
        else
        {
            multiset<int>::iterator it=q[root].find(z);q[root].erase(it);
            if (!q[root].empty())
            {
                it=q[root].end();it--;
                xds[root].Max=*it;xds[root].cost=begin;
            }
            else xds[root].Max=xds[root].cost=0;
        }
        return;
    }
    int mid=(begin+end)/2;
    if (wz<=mid)
    {
        if (!xds[root].ls)xds[root].ls=++cnt;
        gengxin(xds[root].ls,begin,mid,wz,z,u);
    }
    else
    {
        if (!xds[root].rs)xds[root].rs=++cnt;
        gengxin(xds[root].rs,mid+1,end,wz,z,u);
    }
    if (xds[xds[root].ls].Max>=xds[xds[root].rs].Max)
    {
        xds[root].Max=xds[xds[root].ls].Max;
        xds[root].cost=xds[xds[root].ls].cost;
    }
    else
    {
        xds[root].Max=xds[xds[root].rs].Max;
        xds[root].cost=xds[xds[root].rs].cost;
    }
}
void chaxun(int root,int begin,int end,int begin2,int end2){
    if (begin>end2 || end<begin2)return;
    if (begin>=begin2 && end<=end2)
    {
        if (xds[root].Max>Max)
        {
            Max=xds[root].Max;cost=xds[root].cost;
        }
        return;
    }
    int mid=(begin+end)/2;
    chaxun(xds[root].ls,begin,mid,begin2,end2);chaxun(xds[root].rs,mid+1,end,begin2,end2);
}
int main()
{
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++){scanf("%d%d",&w[i],&p[i]);gengxin(1,1,INF,p[i],w[i],1);}
    for (int i=1;i<=m;i++)
    {
        int op;
        scanf("%d",&op);
        if (op==1)
        {
            int x,ww,pp;
            scanf("%d%d%d",&x,&ww,&pp);
            gengxin(1,1,INF,p[x],w[x],0);
            p[x]=pp;w[x]=ww;
            gengxin(1,1,INF,p[x],w[x],1);
        }
        else
        {
            int k;long long ans=0;
            scanf("%d",&k);
            while(1)
            {
                Max=0;cost=0;chaxun(1,1,INF,1,k);
                if (Max)
                {
                    ans+=(long long)k/cost*Max;
                    k=k-k/cost*cost;
                }
                else break;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/1124828077ccj/p/12286656.html