【数据结构】【范浩强Treap】CF702F T-shirt

来源:互联网 发布:正规淘宝刷平台免费 编辑:程序博客网 时间:2024/06/03 14:22

题目大意:

有n件T-shirt,每件T-shirt有一个val值和price值
还有m个顾客,每个顾客有一个最大金额Bi
每个顾客的购买策略是相同的:
他会买他的资金范围内val值最大的一件,
而且每种T-shirt都只能买1次
直到所有的T-shirt他都买不起或者他都买过了,那么

n,m<=100000

分析

其实这道题的难点主要在第一步,就是如何建树,
很容易就会想到用T-shirt来建树,但是这样的话其实是很难做的(反正我没想出来)
因为你既要考虑不能重复买,又不能很容易地做到满足时间复杂度

换一种思路,用人的钱来建平衡树
这样一来就很容易了,因为每个人买衣服的策略是一样的
所以如果按照T-shirt的优先级排序,再依次考虑,就会显得很简单

假设当前考虑到第i件T-shirt,其price值为Pi
那么很容易想到,在平衡树中所有权值大于Pi的点,
都要减去Pi,这样一来,我们就要考虑平衡树区间加减就可以了

那么如何用神奇的范浩强Treap来处理平衡树的区间加减呢?
画个图分析一下(肥肠抱歉,下面两个图Pi写成了Vi):
这里写图片描述
这里写图片描述
很容易发现,平衡树中减去Pi后会有值域重复部分,这样的部分不可能通过Merge操作来完成
那么要怎么做呢????

其实很简单,暴力地将其中一部分中每个节点依次插入平衡树即可。
你是不是本能地认为会超时?
然而,经过很简单的证明,可以得到是不会超时的。

Bi为第i个人的金额,Pi为他需要支付的钱
那么如果这个人需要暴力插入,那么必须满足:

PiBi2Pi

所以
Bi2Pi

要知道的是,Bi每次操作后都需要减去Pi,简而言之,如果要暴力操作,那么Bi至少要减去它的一半,所以最多会被暴力log(Bi)次,就不会超时了

我的范浩强Treap的模板比较丑,下面这个代码卡时限卡得非常紧,因此加了一堆优化,但主体思路并没变。

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<cmath>#define SF scanf#define PF printf#define MAXN 200010using namespace std;struct node{    int ch[2];    int key,fix,sum,add,cnt,cnts;    int id;    node() {}    node(int key1,int id1):key(key1),fix(rand()),sum(1),add(0),cnt(0),cnts(0),id(id1) {}}Tree[MAXN];int root,ncnt;void update(int x){    Tree[x].sum=Tree[Tree[x].ch[0]].sum+Tree[Tree[x].ch[1]].sum+1;    Tree[x].cnt+=Tree[x].cnts;    Tree[x].key+=Tree[x].add;    if(Tree[x].ch[0]){        Tree[Tree[x].ch[0]].add+=Tree[x].add;        Tree[Tree[x].ch[0]].cnts+=Tree[x].cnts;    }    if(Tree[x].ch[1]){        Tree[Tree[x].ch[1]].add+=Tree[x].add;        Tree[Tree[x].ch[1]].cnts+=Tree[x].cnts;    }    Tree[x].cnts=0;    Tree[x].add=0;}int Merge(int x,int y){    if(x==0) return y;    if(y==0) return x;    update(x);    update(y);    if(Tree[x].fix<Tree[y].fix){        Tree[x].ch[1]=Merge(Tree[x].ch[1],y);        update(x);        return x;    }    else{        Tree[y].ch[0]=Merge(x,Tree[y].ch[0]);        update(y);        return y;    }}pair<int,int> Split(int x,int k){    if(x==0) return make_pair(0,0);    pair<int,int> y;    update(x);    if(Tree[x].key<=k){        y=Split(Tree[x].ch[1],k);        Tree[x].ch[1]=y.first;        update(x);        y.first=x;    }    else{        y=Split(Tree[x].ch[0],k);        Tree[x].ch[0]=y.second;        update(x);        y.second=x;    }    return y;}void Insert(int val,int id){    Tree[++ncnt]=node(val,id);    Tree[ncnt].ch[0]=0;    Tree[ncnt].ch[1]=0;    root=Merge(root,ncnt);}void dfs1(int x){    if(x==0)        return ;    update(x);    dfs1(Tree[x].ch[0]);    dfs1(Tree[x].ch[1]);    Tree[x].ch[0]=0;    Tree[x].ch[1]=0;    pair<int,int> y=Split(root,Tree[x].key);    root=Merge(Merge(y.first,x),y.second);}void solve(int val){    pair<int,int> x=Split(root,val-1);    Tree[x.second].add-=val;    Tree[x.second].cnts++;    //PF("[%d %d]",x.first,x.second);    pair<int,int> y=Split(x.second,val);    if(Tree[x.first].sum<Tree[y.first].sum){        root=Merge(y.first,y.second);        dfs1(x.first);    }    else{        root=Merge(x.first,y.second);        dfs1(y.first);    }}int ans[MAXN];void dfs(int x,int sum){    if(x==0)        return ;    ans[Tree[x].id]=sum+Tree[x].cnt+Tree[x].cnts;    dfs(Tree[x].ch[0],sum+Tree[x].cnts);    dfs(Tree[x].ch[1],sum+Tree[x].cnts);}int n,m,x,id;pair<int,int> p[MAXN];void Read(int &x){    char c;    bool flag=0;    while(c=getchar(),c!=EOF&&(c<'0'||c>'9')&&c!='-')    if(c=='-'){        c=getchar();        flag=1;    }    x=c-'0';    while(c=getchar(),c!=EOF&&c>='0'&&c<='9')        x=x*10+c-'0';}pair<int,int> cost[MAXN];int main(){    srand(32);    SF("%d",&n);    for(int i=1;i<=n;i++){        Read(p[i].second);        Read(p[i].first);        p[i].first*=-1;    }    sort(p+1,p+1+n);    SF("%d",&m);    for(int i=1;i<=m;i++){        SF("%d",&cost[i].first);        cost[i].second=i;    }    sort(cost+1,cost+1+m);    for(int i=1;i<=m;i++)        Insert(cost[i].first,cost[i].second);    for(int i=1;i<=n;i++){        /*for(int j=1;j<=m;j++)            PF("[%d %d %d %d %d]lson:%d  rson:%d\n",j,Tree[j].key,Tree[j].add,Tree[j].cnt,Tree[j].cnts,Tree[j].ch[0],Tree[j].ch[1]);        PF("------------------------------------\n");*/        solve(p[i].second);    }    dfs(root,0);    for(int i=1;i<=m;i++)        PF("%d ",ans[i]);}