codeforces 702F T-shirt

来源:互联网 发布:淘宝砍价技巧分享 编辑:程序博客网 时间:2024/05/20 02:27

题目大意

给出n件T-shirt的重要程度q[i]和花费c[i],有k个人最开始分别有b[i]的金钱,每个人的选衣服的策略都是一样的:将所有T-shirt按照重要程度从大到小排序,重要程度相同的按花费从小到大排,然后每个人从头开始取T-shirt,如果金钱数大于当前的T-shirt的花费,那么就买下这件衣服,问每个人最多能够买的T-shirt数量。

暴力

暴力很显然,就是一个个枚举吧。
另外一种暴力是这样的:从前开始枚举每一件T-shirt,枚举当前的所有人剩下的钱,然后减去可以买的。

可持久化Treap

根据第二种暴力,我们可以用一棵可持久化Treap来维护所有人剩下的钱数,对于当前枚举的一件T-shirt,我们可以将Treap split掉,分成大于等于c[i](设为A)和小于c[i](设为B)两部分,然后将A的减掉c[i],然后我们考虑合并两部分,由于Treap的合并要满足一棵树的点权要完全小于第二棵树的点权,于是我们要暴力把A中小于B中最大值的点加到B中,然后就merge一下。
为什么这样的时间复杂度是可行的呢?
考虑一个要加到B中的点x,假设我们原来值为b,那么减完之后就变成了b-c[i],再设B中最大值为a
bc[i]<aa<c[i]bc[i]<c[i]12b<c[i]的,所以每个数最多会被暴力加到B中log2n次,所以总的时间复杂度是O(n(log2n)2)的。

第一次打可持久化Treap
哈哈哈跑得比富榄快
附图:
这里写图片描述
这里写图片描述

贴个标程(PS:由于我的del删的都是最小的点所以写成了另外一种样子):

#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<cstring>#define fo(i,a,b) for(int i=a;i<=b;i++)#define fd(i,a,b) for(int i=a;i>=b;i--)#define fi first#define se secondusing namespace std;typedef long long LL;typedef double db;int get(){    char ch;    int s=0;    while(ch=getchar(),ch<'0'||ch>'9');    s=ch-'0';    while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0';    return s;}typedef pair<int,int> P;const int N = 2e+5+10;struct T_shirts{    int c,q;}a[N];struct point{    int l,r,size,key,v,ad,num,ans,d;//ad for v;d for ans}tree[N];int n,k,root,tot;int ans[N];bool cmp(T_shirts a,T_shirts b){    if (a.q!=b.q)return a.q>b.q;    return  a.c<b.c;}void down(int now){    int l=tree[now].l,r=tree[now].r;    if (tree[now].ad){        if (l){tree[l].ad+=tree[now].ad;tree[l].v-=tree[now].ad;}        if (r){tree[r].ad+=tree[now].ad;tree[r].v-=tree[now].ad;}        tree[now].ad=0;    }    if (tree[now].d){        if (l){tree[l].ans+=tree[now].d;tree[l].d+=tree[now].d;}        if (r){tree[r].ans+=tree[now].d;tree[r].d+=tree[now].d;}        tree[now].d=0;    }}void change(int now){    tree[now].size=tree[tree[now].l].size+tree[tree[now].r].size+1;}int merge(int x,int y){    if (!x||!y)return x^y;    down(x);down(y);    if (tree[x].key<tree[y].key){        tree[x].r=merge(tree[x].r,y);        change(x);        return x;    }    else{        tree[y].l=merge(x,tree[y].l);        change(y);        return y;    }}P split(int now,int tot){    if (!tot)return P(0,now);    down(now);    if (tree[tree[now].l].size>=tot){        P f=split(tree[now].l,tot);        tree[now].l=f.se;        change(now);        return P(f.fi,now);    }    P f=split(tree[now].r,tot-tree[tree[now].l].size-1);    tree[now].r=f.fi;    change(now);    return P(now,f.se);}int gettot(int now,int v){    down(now);    if (!now)return 0;    if (tree[now].v>=v)return gettot(tree[now].l,v);    return gettot(tree[now].r,v)+tree[tree[now].l].size+1;}void insert(int &now,int v,int ans,int num,int w){    int s=gettot(now,v);    P f=split(now,s);    int u=f.fi,e=f.se;    tree[w].v=v;    tree[w].ans=ans;    tree[w].num=num;    tree[w].key=rand();    tree[w].size=1;    u=merge(u,w);    now=merge(u,e);}void del(int &now,int x){    P f=split(now,1);    now=f.se;}int kth(int now,int k){    down(now);    if (tree[tree[now].l].size+1==k)return now;    if (k<=tree[tree[now].l].size)return kth(tree[now].l,k);    return kth(tree[now].r,k-tree[tree[now].l].size-1);}void init(){    n=get();    srand(116786);    fo(i,1,n){a[i].c=get();a[i].q=get();}    sort(a+1,a+1+n,cmp);    k=get();    fo(i,1,k){        if(i==1){            tot=root=tree[1].size=tree[1].num=1;            tree[1].v=get();            tree[1].key=rand();        }        else{            int x=get();            insert(root,x,0,i,i);        }    }}void work(){    fo(i,1,n){        int s=gettot(root,a[i].c);        P f=split(root,s);        int u=f.fi,v=f.se;        if (!v){root=u;continue;}        tree[v].d++;        tree[v].ans++;        tree[v].ad+=a[i].c;        tree[v].v-=a[i].c;        if (!u){root=v;continue;}        int mv=tree[kth(u,tree[u].size)].v;        for(int x=kth(v,1);tree[x].v<mv&&v;x=kth(v,1)){            del(v,x);            insert(u,tree[x].v,tree[x].ans,tree[x].num,tree[x].num);            if (!v)break;        }        if (!v){root=u;continue;}        root=merge(u,v);    }}void getans(int now){    down(now);    if (tree[now].l)getans(tree[now].l);    if (tree[now].r)getans(tree[now].r);    ans[tree[now].num]=tree[now].ans;}void putans(){    getans(root);    fo(i,1,k)printf("%d ",ans[i]);putchar('\n');}int main(){    init();    work();    putans();    return 0;}
2 0
原创粉丝点击