BZOJ1503 [NOI2004]郁闷的出纳员

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1503

【我的感受】

这题郁闷了很久,因为discuss里讨论的问题和我都不是一个问题...

discuss里的当然是一大坑点啦,就是初始工资挂了的不算在最后踢出的人数中。

不过这个我倒是刚开始就这么打的...不过我一直超时啊超时啊...

终于要来了数据...额,原来是平衡树的性质都没怎么用...根本没转几次啊,然后数据就特意卡了这个,连续添加递增工资的人[变成了链]

那我就随机转一转好了,然后不知道为什么不能srand(time(0)),反正这样就会RE,于是干脆不加随机种子了,终于搞定了...

 

【分析】

这题我的思路大概是这样的:

1.因为不管是加工资还是减工资还是加成员还是问第k大,都和数据的数值有关而与顺序无关,于是按数值大小建立二叉树

2.这题和平常做的+tag的题只有一种区别,就是删除和减工资一起执行了。于是需要将会被删掉的人事先找出来,即 工资<最低工资+扣减工资 的人,这当然是一颗子树啦,删掉就好。

3.其它的操作就和之前的一样了,因为每次的增工资和减工资都是对所有人进行,所以相对大小不会变,下次如果将区间增加值...那就麻烦大了[怎么做呢?我自然是想不到了...]

 

#include<cstdio>
#include<ctime>
#include<cstring>
#include<cstdlib>
#include<algorithm>

using namespace std;

inline int in(){
    int x=0;char ch=getchar();
    while(ch>'9' || ch<'0') ch=getchar();
    while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
    return x;
}

const int maxn=100010;

struct Node{
    int f,ch[2];
    int sz,ct;
    int dt,pt;
}s[maxn];

int m,Min,n,rt;

void push_down(int x){
    if(!s[x].pt) return;
    if(s[x].ch[0]) s[s[x].ch[0]].dt+=s[x].pt,s[s[x].ch[0]].pt+=s[x].pt;
    if(s[x].ch[1]) s[s[x].ch[1]].dt+=s[x].pt,s[s[x].ch[1]].pt+=s[x].pt;
    s[x].pt=0;
}

void update(int x){
    s[x].sz=s[s[x].ch[0]].sz+s[s[x].ch[1]].sz+s[x].ct;
}

int Find(int k){
    int p=rt;
    if(s[rt].sz<k || k<=0) return -1;
    while(p){
        push_down(p);
        if(k<=s[s[p].ch[0]].sz) p=s[p].ch[0];
        else{
            k-=s[s[p].ch[0]].sz;
            if(k<=s[p].ct) return p;
            k-=s[p].ct;p=s[p].ch[1];
        }
    }
}

void Rotate(int x,int k){
    int y=s[x].f;s[x].f=s[y].f;
    if(s[y].f){
        if(s[s[y].f].ch[0]==y) s[s[y].f].ch[0]=x;else s[s[y].f].ch[1]=x;}
    s[y].ch[k]=s[x].ch[k^1];
    if(s[x].ch[k^1]) s[s[x].ch[k^1]].f=y;
    s[y].f=x,s[x].ch[k^1]=y;
    update(y),update(x);
}

void Splay(int x,int gf){
    int y;
    while(s[x].f!=gf){
        y=s[x].f;
        if(s[y].f==gf){
            if(x==s[y].ch[0]) Rotate(x,0); else Rotate(x,1);}
        else{
            int z=s[y].f;
            if(y==s[z].ch[0]){
                if(x==s[y].ch[0]) Rotate(y,0),Rotate(x,0);else Rotate(x,1),Rotate(x,0);}
            else{
                if(x==s[y].ch[1]) Rotate(y,1),Rotate(x,1);else Rotate(x,0),Rotate(x,1);}
        }
    }
    if(!gf) rt=x;
}

void Insert(int x){
    if(x<Min) return;
    if(!rt){s[++n].dt=x;s[n].sz=1;rt=n,s[n].ct=1;return;}
    int p=rt;
    while(p){
        s[p].sz++;
        push_down(p);
        if(s[p].dt<x){
            if(s[p].ch[1]) p=s[p].ch[1];
            else{
                s[p].ch[1]=++n,s[n].dt=x,s[n].sz=1,s[n].f=p,s[n].ct=1;break;
            }
        }
        else if(s[p].dt>x){
            if(s[p].ch[0]) p=s[p].ch[0];
            else{
                s[p].ch[0]=++n,s[n].dt=x,s[n].sz=1,s[n].f=p,s[n].ct=1;break;
            }
        }
        else{
            n++;s[p].ct++;return;
        }
    }
    if(rand()%100>80) Splay(n,0);
}

void Addition(int x){
    s[rt].dt+=x,s[rt].pt+=x;
}

void Shorten(int x){
    int p=rt,bye=Min+x,rec=-1;
    while(p){
        push_down(p);
        if(s[p].dt<bye)
            rec=p,p=s[p].ch[1];
        else
            p=s[p].ch[0];
    }
    if(rec!=-1){
        Splay(rec,0);
        rt=s[rec].ch[1],s[rt].f=0;
        if(rt) update(rt);
    }
    if(rt) s[rt].dt-=x,s[rt].pt-=x;
}

int Get_kth(int k){
    int x=Find(s[rt].sz-k+1);
    if(x<0) return -1;
    if(rand()%100>80) Splay(x,0);
    return s[x].dt;
}

int main(){
#ifndef ONLINE_JUDGE
    freopen("1503.in","r",stdin);
    freopen("1503.out","w",stdout);
#endif
    
    int k;
    char ord[2];
    
    scanf("%d%d",&m,&Min);
    while(m--){
        scanf("%s",ord);k=in();
        if(ord[0]=='I') Insert(k);
        else if(ord[0]=='A') Addition(k);
        else if(ord[0]=='S') Shorten(k);
        else if(ord[0]=='F') printf("%d\n",Get_kth(k));
    }
    printf("%d",n-s[rt].sz);
    
    return 0;
}
View Code

 

posted @ 2015-12-30 20:09  诚叙  阅读(188)  评论(0编辑  收藏  举报