题意:
有n个商品,每个商品有一个价格和价值。m次操作,每次更改一个商品的信息或者询问一个k,表示一开始有k元钱,然后问会买到价值多少的商品。
购买方式很特别,分若干轮,每一轮从我能买的物品中选择一个价值最大的(相同的选择价格最小的),然后买下它,重复上述操作,直到买不了任何东西。
n,m<=100000,其余数值<=1000000000。
题解:
如果每次只买一轮,那么问题很简单,使用权值线段树维护商品价值最大值即可。
那么如果要买很多轮,那对于每一轮,会买到一个商品,这个商品是能买到的价值最大的。
这意味着什么,意味着下一轮如果有能力购买它,依然会选择它。也就是说,找到一个要买的物品,然后一直买直到钱不够买它为止(这个价值可以直接计算),再进行下一轮购买。
这样的效率就是m*log*操作的轮数。可以证明,按照这样的方法操作,操作次数不会超过log2(1000000000)。
证明也很容易,如果这个商品的价格>手里钱数的一半,那减掉他之后钱数至少减半。如果商品价格<手里钱数的一半,那会一直买它直到买不起,那么最后钱数也会<商品价格<原来钱数的一半。所以每次钱数至少减半,那么操作次数就是log次。
还有个修改操作,由于物品的价格可能会相同,所以在线段树的每一个叶子上面要开一个multiset来记录商品,用于增加和删除。
#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 ",ans); } } return 0; }