BZOJ 1503: [NOI2004]郁闷的出纳员

这道题还不如叫郁闷的楼主。

因为没看清楚题目要求的是找出第K大的数(而不是第K小数),然后SB的DEBUG了4个小时。。。。

好吧,讲讲思路。

首先是输入,当这个人的起始工资是小于最小额的时候,是不能makefile的,所以这个人数也不用统计。

关于增加工资和减少工资,我们可以开另外一个变量add来存,每次减少工资的时候,delete掉当前工资小于MIN - add的人。

这道题主要考虑的还是Splay树的基本操作,当然对于我这种弱菜才需要DEBUG这么久。。。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstring>
#include <queue>
#include <set>
#include <vector>
#include <stack>
#include <map>
#include <iomanip>
#define PI acos(-1.0)
#define Max 2505
#define inf 1<<28
#define LL(x) (x<<1)
#define RR(x) (x<<1|1)
#define REP(i,s,t) for(int i=(s);i<=(t);++i)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define mp(a,b) make_pair(a,b)
#define PII pair<int,int>
using namespace std;

int root , tot ;
int fa[1111111] , ch[1111111][2] ,data[1111111] , num[1111111]  ;
int n , m ;
void push_up(int x) {
    num[x] = num[ch[x][0]] + num[ch[x][1]] + 1 ;
}

void rotate(int x ,int kind) {
    int y = fa[x] ;

    ch[y][!kind] = ch[x][kind] ;
    fa[ch[x][kind]] = y ;
    if(fa[y])ch[fa[y]][ch[fa[y]][1] == y] = x ;
    fa[x] = fa[y] ;
    ch[x][kind] = y ;
    fa[y] = x ;
    push_up(y) ;
    push_up(x) ;
}
void Splay(int x ,int s ) { //将节点x转到节点s下面
    //push_down(x) ;
    while(fa[x] != s) {
        if(fa[fa[x]] == s)rotate(x ,ch[fa[x]][0] == x) ;
        else {
            int y = fa[x] ;
            int z = fa[y] ;
            int kind = ( ch[z][0] == y );
            if(ch[y][kind] == x) {
                rotate(x ,!kind ) ;
                rotate(x , kind ) ;
            } else {
                rotate(y , kind ) ;
                rotate(x , kind ) ;
            }
        }
    }
    push_up(x) ;
    if(s == 0)root = x ;
}

void insert(int x) {
    if(!root) {
        root = ++ tot ;
        data[root] = x ;
        fa[root] = 0 ;
        ch[root][0] = ch[root][1] = 0 ;
        num[root] = 1 ;
        return ;
    }
    int xx = root ;
    int yy ;
    while(xx) {
        yy = xx ;
        num[xx] ++ ;
        if(x < data[xx]) {
            xx = ch[xx][0] ;
        } else {
            xx = ch[xx][1] ;
        }
    }
    if(x < data[yy]) {
        ch[yy][0] = ++ tot ;
    } else {
        ch[yy][1] = ++ tot ;
    }
    fa[tot] = yy ;
    data[tot] = x ;
    num[tot] = 1 ;
    Splay(tot ,0) ;
    return ;
}
int ans = 0 ;
void Delete(int k) {
    int x = root ;
    int xx = 0 ;
    while(x) {
        if(data[x] < k) {
            xx = x ;
            x = ch[x][1] ;
        } else {
            x = ch[x][0] ;
        }
    }
    if(!xx)return ;
    Splay(xx , 0) ;
    if(ch[xx][1] == 0) {
        root = 0 ;
        return ;
    }

    root = ch[xx][1] ;
    fa[root] = 0 ;
}
int addd = 0 ;
void get_K(int k ) {
    if(k < 1) {
        printf("-1\n") ;
        return ;
    }
    int x = root ;
    while(ch[x][0] || ch[x][1]) {
        if(k == num[ch[x][0]] + 1)break ;
        else if(k < num[ch[x][0]] + 1) {
            x = ch[x][0] ;
        } else {

            k -= num[ch[x][0]] + 1 ;
            x = ch[x][1] ;
        }
    }
    printf("%d\n",data[x] + addd) ;
    return ;
}

void Treaval(int x) {
    if(x) {
        Treaval(ch[x][0]);
        printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,key = %2d \n",x,ch[x][0],ch[x][1],fa[x],num[x],data[x] + addd);
        Treaval(ch[x][1]);
    }
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("D:\\acm.txt","r",stdin) ;
#endif
    scanf("%d%d",&n,&m) ;
    ans = 0 ;
    addd = 0 ;
    char op ;
    tot = root = 0 ;
    int first = 0 ;
    int cc = n ;
    int xx ;
    int people = 0 ;
    REP(i , 0 , n - 1) {
        scanf("\n") ;
        scanf("%c %d",&op,&xx) ;
        if(op == 'I' && xx >= m) { //build a new file
            insert(xx - addd) ;
            people ++ ;
            first = 1 ;
        } else if(op == 'A') { //add the money
            addd += xx ;

        } else if(op == 'S') { //decrease the money
            addd -= xx ;
            Delete(m - addd) ;
        } else if(op == 'F') { //print the kth money
            get_K(num[root] - xx + 1) ;
        }
    }
    printf("%d\n",people - num[root]) ;
    return 0 ;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值