ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CF702F T-Shirts

2019-12-03 11:51:41  阅读:271  来源: 互联网

标签:钱数 lc int tag Shirts laz rc CF702F


题目
考虑把商品按质量排序之后一个个处理,这样能买当前商品的人就是拥有钱数大于等于当前商品价格的人。
那么我们现在需要支持的就是把所有剩余钱数\(\ge k\)的人钱数\(-k\),答案\(+1\)。
这东西看上去并不是那么好做,我们有一个比较优雅的结合暴力的平衡树做法。
加入当前物品的钱数是\(c_i\)。
我们把所有人按钱数分为三类:\([0,c_i),[c_i,2c_i),[2c_i,+\infty)\)。
然后我们会发现,第一类人啥也买不起,所以他们答案和钱数都不变。
第二类人答案会\(+1\),买了一件之后钱数也到了\([0,c_i)\)的范围。
而第三类人答案也会\(+1\),并且买了一件之后钱数到了\([c_i,+\infty)\)的范围。
也就是说,第三类人买完之后钱数一定比第一类、第二类人多。
这启发我们用fhq Treap,以钱数为关键字维护hfq Treap,同时记录每个人的答案。
对于没件商品,我们按照钱数把fhq Treap分裂成三个。
对于第三类人,我们可以直接打标记。
对于第一类人,我们啥也不用做。
对于第二类人,我们暴力地修改他们每个人的钱数和答案,并暴力地跟第一类人合并。
最后把第一类和第三类merge回来。
因为每次暴力合并剩余钱数至少会减半,所以一个人最多被暴力合并\(\log b\)次。
因此总的复杂度为\(O(n\log n\log b)\)。

#include<bits/stdc++.h>
#define lc ch[p][0]
#define rc ch[p][1]
using namespace std;
namespace IO
{
    char ibuf[(1<<21)+1],obuf[(1<<21)+1],st[11],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
    void Put(char x){*oS++=x;if(oS==oT)Flush();}
    int read(){int x=0,c=Get(),f=0;while(!isdigit(c)&&c^'-')c=Get();if(c=='-')f=1,c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return f? -x:x;}
    void write(int x){int top=0;if(!x)Put('0');if(x<0)Put('-'),x=-x;while(x)st[++top]=(x%10)+48,x/=10;while(top)Put(st[top--]);Put(' ');}
}
using namespace IO;
void swap(int &x,int &y){x^=y^=x^=y;}
const int N=200007;
struct node{int c,q;}T[N];queue<int>q;
int n,m,ch[N][2],laz[N],tag[N],sum[N],val[N],dat[N],root,tot,x,y,z;
int New(int x){return val[++tot]=x,dat[tot]=rand(),tot;}
void pushdown(int p)
{
    if(laz[p])
    {
    if(lc) sum[lc]+=laz[p],laz[lc]+=laz[p];
    if(rc) sum[rc]+=laz[p],laz[rc]+=laz[p];
    laz[p]=0;
    }
    if(tag[p])
    {
    if(lc) val[lc]-=tag[p],tag[lc]+=tag[p];
    if(rc) val[rc]-=tag[p],tag[rc]+=tag[p];
    tag[p]=0;
    }
}
void split(int p,int k,int &x,int &y)
{
    if(!p) return (void)(x=y=0);
    pushdown(p),val[p]<=k? (x=p,split(rc,k,rc,y)):(y=p,split(lc,k,x,lc));
}
int merge(int x,int y)
{
    if(!x||!y) return x+y;
    return dat[x]<dat[y]? (pushdown(x),ch[x][1]=merge(ch[x][1],y),x):(pushdown(y),ch[y][0]=merge(x,ch[y][0]),y);
}
void update(int p)
{
    pushdown(p);
    if(lc) update(lc);
    if(rc) update(rc);
}
int main()
{
    n=read();
    for(int i=1;i<=n;++i) T[i].c=read(),T[i].q=read();
    sort(T+1,T+n+1,[](node a,node b){return a.q>b.q||(a.q==b.q&&a.c<b.c);}),m=read();
    for(int i=1,v;i<=m;++i) v=read(),split(root,v,x,y),root=merge(merge(x,New(v)),y);
    for(int i=1,p,a,b;i<=n;++i)
    {
    while(!q.empty()) q.pop();
    split(root,T[i].c-1,x,y),split(y,T[i].c*2-1,y,z);
    ++sum[z],++laz[z],val[z]-=T[i].c,tag[z]+=T[i].c;
    if(y) q.push(y);
    for(;!q.empty();)
    {
        p=q.front(),q.pop(),pushdown(p);
        if(lc) q.push(lc);
        if(rc) q.push(rc);
        lc=rc=laz[p]=tag[p]=0,++sum[p],val[p]-=T[i].c;
        split(x,val[p],a,b),x=merge(merge(a,p),b);
    }
    root=merge(x,z);
    }
    update(root);
    for(int i=1;i<=m;++i) write(sum[i]);
    return Flush(),0;
}

标签:钱数,lc,int,tag,Shirts,laz,rc,CF702F
来源: https://www.cnblogs.com/cjoierShiina-Mashiro/p/11975926.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有