【平衡树】BZOJ1503(NOI2004)[郁闷的出纳员]题解

题目概述

这里写图片描述
ps:员工一旦发现自己的工资低于工资下界,就会离开公司,再也不会回来了。

解题报告

这道题有插入有删除且求第k大显然用平衡树做,只不过加工资和减工资不是很常规的操作。想一想可以发现加工资和减工资用Lazy-tag就可以解决,但是实际上并不需要,因为加工资和减工资表面看上去是员工工资的变化,实际上我们也可以看做是工资下界发生了变化!所以我们不用去调整每个员工的工资,只需要调整工资下界即可,但这样一来新员工的工资就不是读入的工资了,要加上当前工资下界MIN减去最初工资下界fst,同理,查询的答案也需要减去MIN-fst。
比较坑爹的是,新员工如果工资直接比工资下界低离开公司,是不算入离开人数的……

由于最近学了下SBT,于是SBT和Treap都抄板子打了一遍……

示例程序

Treap

#include<cstdio>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int MAXINT=((1<<30)-1)*2+1,maxn=100000;

int te,fst,MIN,ans;
struct Treap
{
    Treap* son[2];int x,w,si,p;
    Treap(int K,Treap* P,int S=1) {si=w=S;x=K;son[0]=son[1]=P;p=rand();}
    int cmp(int k) {if (k<x) return 0;if (k==x) return -1;if (k>x) return 1;}
    void Pushup() {si=son[0]->si+son[1]->si+w;}
};
Treap nil(0,&nil,0),*null=&nil,*ro=null;

void Rotate(Treap* &id,int d)
{
    Treap* t=id->son[d^1];id->son[d^1]=t->son[d];t->son[d]=id;
    id->Pushup();t->Pushup();id=t;
}
void Insert(Treap* &id,int x)
{
    if (id==null) {id=new Treap(x,null);return;}
    int d=id->cmp(x);
    if (d==-1) id->w++; else
    {
        Insert(id->son[d],x);
        if (id->son[d]->p>id->p) Rotate(id,d^1);
    }
    id->Pushup();
}
void Delete(Treap* &id,int x)
{
    if (id==null) return;
    int d=id->cmp(x);
    if (d==-1)
    {
        if (id->w>1) id->w--; else
        if (id->son[0]==null) id=id->son[1]; else
        if (id->son[1]==null) id=id->son[0]; else
        {
            int son;if (id->son[0]->p>id->son[1]->p) son=0; else son=1;
            Rotate(id,son^1);if (id==null) return;
            Delete(id->son[son^1],x);
        }
        if (id==null) return;
    } else Delete(id->son[d],x);
    id->Pushup();
}
int getkth(Treap* id,int k)
{
    if (id==null) return -1;
    if (id->son[0]->si<k&&k<=id->son[0]->si+id->w) return id->x-MIN+fst; else
    if (k<=id->son[0]->si) return getkth(id->son[0],k); else
    return getkth(id->son[1],k-(id->son[0]->si+id->w));
}
int getpre(Treap* id,int k)
{
    if (id==null) return -MAXINT;
    int d=id->cmp(k);
    if (d==1)
    {
        int now=id->x,tem=getpre(id->son[1],k);
        if (tem!=-MAXINT) return tem; else return now;
    } else return getpre(id->son[0],k);
}

char readc()
{
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF; else return *l++;
}
bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
int readi(int &x)
{
    int tot=0,f=1;char ch=readc(),lst=ch;
    while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
    if (lst=='-') f=-f;
    while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
    x=tot*f;
    return Eoln(ch);
}
char getrch() {char ch=readc();while ('Z'<ch||ch<'A') ch=readc();return ch;}
int main()
{
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    readi(te);readi(fst);MIN=fst;
    while (te--)
    {
        int x;
        switch(getrch())
        {
            case 'I':readi(x);if (x+MIN-fst>=MIN) Insert(ro,x+MIN-fst);break;
            case 'A':readi(x);MIN-=x;break;
            case 'S':readi(x);MIN+=x;break;
            case 'F':readi(x);x=ro->si-x+1;printf("%d\n",getkth(ro,x));break;
        }
        for (int now=getpre(ro,MIN);now!=-MAXINT;now=getpre(ro,MIN))
            Delete(ro,now),ans++;
    }
    printf("%d\n",ans);
    return 0;
}

SBT

#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXINT=((1<<30)-1)*2+1;

int te,fst,MIN,ans;
struct node
{
    node* son[2];int si,key;
    node(int k,node* p,int s=1) {si=s;key=k;son[0]=son[1]=p;}
    int cmp(int k) {return k>=key;}
    void Pushup() {si=son[0]->si+1+son[1]->si;}
};
node nil(0,&nil,0);
typedef node* P_node;
P_node null=&nil,ro=null;
void Rotate(P_node &p,int d)
{
    P_node t=p->son[d^1];p->son[d^1]=t->son[d];t->son[d]=p;
    p->Pushup();t->Pushup();p=t;
}
void Maintain(P_node &p,bool fl)
{
    P_node L=p->son[0],R=p->son[1];
    if (!fl)
        if (L->son[0]->si>R->si) Rotate(p,1); else
        if (L->son[1]->si>R->si) Rotate(p->son[0],0),Rotate(p,1); else
        return;
    else
        if (R->son[1]->si>L->si) Rotate(p,0); else
        if (R->son[0]->si>L->si) Rotate(p->son[1],1),Rotate(p,0); else
        return;
    Maintain(p->son[0],0);Maintain(p->son[0],1);
    Maintain(p->son[1],0);Maintain(p->son[1],1);
    Maintain(p,0);Maintain(p,1);
}
void Insert(P_node &p,int k)
{
    if (p==null) {p=new node(k,null);return;}
    int d=p->cmp(k);Insert(p->son[d],k);
    p->Pushup();Maintain(p,d);
}
int Delete(P_node &p,int k)
{
    int d=p->cmp(k),now;
    if (k==p->key||p->son[d]==null)
    {
        now=p->key;
        if (p->son[0]==null) p=p->son[1]; else
        if (p->son[1]==null) p=p->son[0]; else
        p->key=Delete(p->son[0],p->key),p->Pushup(),Maintain(p,1);
        return now;
    }
    now=Delete(p->son[d],k);
    p->Pushup();Maintain(p,d^1);
    return now;
}
int getkth(P_node p,int k)
{
    if (p==null) return -1;
    if (k==p->son[0]->si+1) return p->key+fst-MIN; else
    if (k<=p->son[0]->si) return getkth(p->son[0],k); else
    return getkth(p->son[1],k-p->son[0]->si-1);
}
int getpre(P_node p,int k)
{
    if (p==null) return -MAXINT;
    if (k>p->key) return max(p->key,getpre(p->son[1],k)); else
    return getpre(p->son[0],k);
}

char readc()
{
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF; else return *l++;
}
bool Eoln(char ch) {return ch==10||ch==13||ch==EOF;}
int readi(int &x)
{
    int tot=0,f=1;char ch=readc(),lst=ch;
    while ('9'<ch||ch<'0') {if (ch==EOF) return EOF;lst=ch;ch=readc();}
    if (lst=='-') f=-f;
    while ('0'<=ch&&ch<='9') tot=tot*10+ch-48,ch=readc();
    x=tot*f;
    return Eoln(ch);
}
char getrch() {char ch=readc();while ('Z'<ch||ch<'A') ch=readc();return ch;}
int main()
{
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    readi(te);readi(fst);MIN=fst;
    while (te--)
    {
        int x;
        switch(getrch())
        {
            case 'I':readi(x);if (x+MIN-fst>=MIN) Insert(ro,x+MIN-fst);break;
            case 'A':readi(x);MIN-=x;break;
            case 'S':readi(x);MIN+=x;break;
            case 'F':readi(x);x=ro->si-x+1;printf("%d\n",getkth(ro,x));break;
        }
        for (int now=getpre(ro,MIN);now!=-MAXINT;now=getpre(ro,MIN))
            Delete(ro,now),ans++;
    }
    printf("%d\n",ans);
    return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值