CF702F T-Shirts

一、题目

点此看题
题目描述
有n种T恤,每种有价格ci和品质qi。有m个人要买T恤,第i个人有vi元,每人每次都会买一件能买得起的qi最大的T恤。一个人只能买一种T恤一件,所有人之间都是独立的。问最后每个人买了多少件T恤?如果有多个qi最大的T恤,会从价格低的开始买。
数据范围
1 ≤ n , m ≤ 2 e 5 1\leq n,m\leq 2e5 1n,m2e5 1 ≤ c , q , v ≤ 1 0 9 1\leq c,q,v\leq 10^9 1c,q,v109

二、解法

0x01 暴力

一个很显然的做法就是先把每件T-shirt以品质为第一关键字,价格为第二关键字排序,对于每一个人的询问在线性扫一遍,能买则买,这种做法不可优化。

0x02 另一种思考

与其去看人能买那些衣服,不如看衣服能被那些人买,我们还是先排序,每次看那些人能买到这种衣服,时间复杂度虽然不降,但是好像能够用 treap \text{treap} treap优化,我们维护一个关于人的平衡树,每次对钱数不小于 c c c的区间修改,但是要考虑一个问题,修改之后不能直接 merge \text{merge} merge,因为不能保证修改后区间的钱数整体不小于另一个区间,那我们就把 c ≤ v < 2 c c\leq v< 2c cv<2c的区间暴力插入,其他的区间插入。

这样的复杂度好像还是会超,但仔细想想,这些被暴力插入的人的钱数至少减少了一半,也就是他们的钱数是以 log ⁡ \log log的速度下降的,每个人最多被单独插入 log ⁡ v \log v logv次,这样时间复杂度就有了保证。

0x03 tips and code
1、最后还要整体下传一次标记。
2、单个插入不要一个一个分裂,把区间分裂出来在一个一个插入(不然会 T T T)。

#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <queue>
using namespace std;
const int MAXN = 200005;
int read()
{
    int x=0,flag=1;
    char c;
    while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
    while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*flag;
}
int n,m,rt;
int ch[MAXN][2],siz[MAXN],ans[MAXN],val[MAXN],hp[MAXN],la[MAXN],ad[MAXN];
struct data
{
    int c,q;
    bool operator < (const data &R) const
    {
        if(q==R.q) return c<R.c;
        return q>R.q;
    }
} s[MAXN];
struct node
{
    int p[2];
    node()
    {
        p[0]=p[1]=0;
    }
} emp;
void up(int x)
{
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
void down(int x)
{
    if(la[x])
    {
        la[ch[x][0]]+=la[x];
        la[ch[x][1]]+=la[x];
        val[ch[x][0]]-=la[x];
        val[ch[x][1]]-=la[x];
        la[x]=0;
    }
    if(ad[x])
    {
        ad[ch[x][0]]+=ad[x];
        ad[ch[x][1]]+=ad[x];
        ans[ch[x][0]]+=ad[x];
        ans[ch[x][1]]+=ad[x];
        ad[x]=0;
    }
}
node split(int x,int v)
{
    if(!x) return emp;
    down(x);
    int d=val[x]<=v;
    node y=split(ch[x][d],v);
    ch[x][d]=y.p[d^1];
    y.p[d^1]=x;
    up(x);
    return y;
}
node split_(int x,int s)
{
    if(!x) return emp;
    down(x);
    node y;
    if(siz[ch[x][0]]>=s)
    {
        y=split_(ch[x][0],s);
        ch[x][0]=y.p[1];
        y.p[1]=x;
    }
    else
    {
        y=split_(ch[x][1],s-siz[ch[x][0]]-1);
        ch[x][1]=y.p[0];
        y.p[0]=x;
    }
    up(x);
    return y;
}
int merge(int x,int y)
{
    if(!x || !y) return x+y;
    if(hp[x]<hp[y])
    {
        down(x);
        ch[x][1]=merge(ch[x][1],y);
        up(x);
        return x;
    }
    down(y);
    ch[y][0]=merge(x,ch[y][0]);
    up(y);
    return y;
}
void ins(int &rt,int i,int v)
{
    node x=split(rt,v-1);
    ch[i][0]=ch[i][1]=0;
    siz[i]=1;
    hp[i]=rand();
    val[i]=v;
    rt=merge(x.p[0],merge(i,x.p[1]));
}
int pre(int &rt,int v)
{
    node x=split(rt,v-1),y=split_(x.p[0],siz[x.p[0]]-1);
    int ans=val[y.p[1]];
    rt=merge(merge(y.p[0],y.p[1]),x.p[1]);
    return ans;
}
void print(int x)
{
    if(!x) return ;
    down(x);
    print(ch[x][0]);
    //printf("%d ",val[x]);
    print(ch[x][1]);
}
int main()
{
    //srand(time(0));
    n=read();
    for(int i=1; i<=n; i++)
    {
        s[i].c=read();
        s[i].q=read();
    }
    sort(s+1,s+1+n);
    m=read();
    for(int i=1; i<=m; i++)
        ins(rt,i,read());
    for(int i=1; i<=n; i++)
    {
        node x=split(rt,s[i].c-1);
        la[x.p[1]]+=s[i].c;
        val[x.p[1]]-=s[i].c;
        ad[x.p[1]]++;
        ans[x.p[1]]++;
        node y=split(x.p[1],2*s[i].c-1);
        queue<int> q;
        q.push(y.p[0]);
        while(!q.empty())
        {
            int t=q.front();
            q.pop();
            down(t);
            if(ch[t][0]) q.push(ch[t][0]);
            if(ch[t][1]) q.push(ch[t][1]);
            ins(x.p[0],t,val[t]);
        }
        rt=merge(x.p[0],y.p[1]);
    }
    print(rt);
    for(int i=1; i<=m; i++)
        printf("%d ",ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值