CF702F-T-Shirts【FhqTreap】

1|0正题

题目链接:https://www.luogu.com.cn/problem/CF702F


1|1题目大意

n个物品,第i个价格为ci,质量为qi

然后有m个询问,假设一个人有vi块,他每次会买他能买得起的qi最大的(如果相同就ci最小的)物品购买,直到买不起为止,一个物品只能买一次,求他最后能买多少个物品。

1n,m2×105,1ci,qi,vi109


1|2解题思路

考虑最暴力的做法,我们可以把所有物品按照qi从大到小排序,然后对于每个人枚举所有物品,如果买得起就买,这样就是O(nm)的了。

考虑如何优化这个做法,在线显然难搞,我们考虑把所有人放在一起维护。

对于物品价格为c,那么所有vic的都有ansi+1,vic

也就是对于一个值域进行操作,考虑到这个值域是动态的,尝试用平衡树维护

那么考虑对于钱数为[0,c1]的人不操作。

对于钱数为[c,2×c1]的人,ansi+1,vic,并且vic<c。也就是说此时减去后范围都在[0,c1],会和原来[0,c1]范围内的人有重复。

对于钱数为[2×c,)的人,ansi+1,vic,并且vicc,也就是说这一部分整体往前移动c位之后不会和其它部分的人有交叉。那么这一部分的人我们可以打一个标记然后插回平衡树中。

那么现在问题是[c,2×c1]部分的人如何操作,注意到此时有vicvi2,也就是一个vi最多操作log次,所以我们可以直接暴力把这一部分提出来然后一个一个插回去。

FhqTreap很轻易实现以上功能

时间复杂度:O(nlognlogv)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=2e5+10; int n,m,root; struct node{ int q,v; }q[N]; struct FHQ_Treap{ int cnt,siz[N],rnk[N],t[N][2]; int w[N],ans[N],lazy1[N],lazy2[N]; int NewNode(int val){ ++cnt;w[cnt]=val;siz[cnt]=1; rnk[cnt]=rand();return cnt; } void PushUp(int x) {siz[x]=siz[t[x][0]]+siz[t[x][1]]+1;return;} void PushDown(int x){ for(int i=0;i<2;i++){ if(!t[x][i])continue; lazy1[t[x][i]]+=lazy1[x]; lazy2[t[x][i]]+=lazy2[x]; w[t[x][i]]+=lazy1[x]; ans[t[x][i]]+=lazy2[x]; } lazy1[x]=lazy2[x]=0; return; } void Split(int &x,int &y,int p,int k){ if(!p){x=y=0;return;}PushDown(p); if(w[p]<=k)x=p,Split(t[x][1],y,t[p][1],k); else y=p,Split(x,t[y][0],t[p][0],k); PushUp(p);return; } int Merge(int x,int y){ PushDown(x);PushDown(y); if(!x||!y)return x|y; if(rnk[x]<rnk[y]){ t[x][1]=Merge(t[x][1],y); PushUp(x);return x; } else{ t[y][0]=Merge(x,t[y][0]); PushUp(y);return y; } } void Ins(int p,int &root){ int x,y; Split(x,y,root,w[p]); root=Merge(Merge(x,p),y); return; } void Deal(int p,int c,int &root){ if(!p)return; PushDown(p); Deal(t[p][0],c,root); Deal(t[p][1],c,root); t[p][0]=t[p][1]=0; ans[p]++;lazy2[p]++; w[p]-=c;lazy1[p]-=c; Ins(p,root); } void Solve(int c){ int x,y,z; Split(x,y,root,c-1); Split(y,z,y,2*c-1); if(z){ ans[z]++;lazy2[z]++; w[z]-=c;lazy1[z]-=c; } root=Merge(x,z); Deal(y,c,root); return; } void Fors(int p){ if(!p)return;PushDown(p); Fors(t[p][0]);Fors(t[p][1]); return; } }T; bool cmp(node x,node y) {return (x.q==y.q)?(x.v<y.v):(x.q>y.q);} int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&q[i].v,&q[i].q); sort(q+1,q+1+n,cmp); scanf("%d",&m); for(int i=1,x;i<=m;i++){ scanf("%d",&x); T.Ins(T.NewNode(x),root); } for(int i=1;i<=n;i++) T.Solve(q[i].v); T.Fors(root); for(int i=1;i<=m;i++) printf("%d ",T.ans[i]); return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15806064.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(30)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
历史上的今天:
2021-01-15 P5325-[模板]Min_25筛
2021-01-15 XJOI-multiset【堆,随机二分】
2021-01-15 XJOI-rotate【欧拉路,模型转换】
点击右上角即可分享
微信分享提示