[郁闷的出纳员] ( Splay树 )

From: http://www.lydsy.com/JudgeOnline/problem.php?id=1503

Input

第一行有两个非负整数nminn表示下面有多少条命令,min表示工资下界。

接下来的n行,每行表示一条命令。命令可以是以下四种之一:

名称

格式

作用

I命令

I_k

新建一个工资档案,初始工资为k。如果某员工的初始工资低于工资下界,他将立刻离开公司。

A命令

A_k

把每位员工的工资加上k

S命令

S_k

把每位员工的工资扣除k

F命令

F_k

查询第k多的工资

_(下划线)表示一个空格,I命令、A命令、S命令中的k是一个非负整数,F命令中的k是一个正整数。

在初始时,可以认为公司里一个员工也没有。

Output

输出文件的行数为F命令的条数加一。

对于每条F命令,你的程序要输出一行,仅包含一个整数,为当前工资第k多的员工所拿的工资数,如果k大于目前员工的数目,则输出-1。

输出文件的最后一行包含一个整数,为离开公司的员工的总数。

Sample Input

9 10
I 60
I 70
S 50
F 2
I 30
S 15
A 5
F 1
F 2

Sample Output

10
20
-1
2

Hint

【约定】

l        I命令的条数不超过100000

l        A命令和S命令的总条数不超过100 

l        F命令的条数不超过100000

l        每次工资调整的调整量不超过1000

l        新员工的工资不超过100000

思路: SPLAY

设d0为最小工资, v是树中节点的代价。

对于S操作, 增量为m, 那么 v - m < d0的都要从树中删除,即 v < m + d0的节点被移除。如何移除这些满足条件的节点?找到不小于m+d0的最大节点x, 把x旋转到根部, 然后把x的右子女作为根,复杂度O(lbn)。

 

/**************************************************************
    Problem: 1503
    User: leezy
    Language: C++
    Result: Accepted
    Time:728 ms
    Memory:3224 kb
****************************************************************/
 
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <cmath>
using namespace std;
#define N 100005
#define M 1000000
#define INF 0x7fffffff
struct { int v,l,r,p,sz; }t[N];
int cnt,root;
int alloc(int v){
    t[++cnt].v = v;
    t[cnt].sz = 1;
    t[cnt].l = t[cnt].r = t[cnt].p = 0;
    return cnt;
}
void rot_l(int x){
    int y = t[x].r;
    t[x].r = t[y].l; t[t[y].l].p = x;
    t[y].p = t[x].p;
    if ( !t[x].p ) root = y;
    else if ( t[t[x].p].l == x ) t[t[x].p].l = y;
    else t[t[x].p].r = y;
    t[y].l = x; t[x].p = y;
    t[y].sz = t[x].sz;
    t[x].sz = t[t[x].l].sz + t[t[x].r].sz + 1;
}
void rot_r(int x){
    int y = t[x].l;
    t[x].l = t[y].r; t[t[y].r].p = x;
    t[y].p = t[x].p;
    if ( !t[x].p ) root = y;
    else if ( t[t[x].p].l == x ) t[t[x].p].l = y;
    else t[t[x].p].r = y;
    t[y].r = x; t[x].p = y;
    t[y].sz = t[x].sz;
    t[x].sz = t[t[x].l].sz + t[t[x].r].sz + 1;
}
void splay(int x){
    while ( t[x].p ){
        int p1 = t[x].p;
        if ( t[p1].l == x ){
            if ( !t[p1].p ) rot_r(p1);
            else {
                int p2 = t[p1].p;
                if ( t[p2].l == p1 ) rot_r(p2), rot_r(p1);
                else rot_r(p1), rot_l(p2);
            }
        } else {
            if ( !t[p1].p ) rot_l(p1);
            else {
                int p2 = t[p1].p;
                if ( t[p2].r == p1 ) rot_l(p2), rot_l(p1);
                else rot_l(p1), rot_r(p2);
            }
        }
    }
}
void ins(int v){
    int x = root, y = 0;
    while ( x ) {
        y = x; ++t[x].sz;
        if ( t[x].v < v ) x = t[x].r;
        else x = t[x].l;
    }
    int k = alloc(v);
    t[k].p = y;
    if ( !y ) root = k;
    else if ( t[y].v < v ) t[y].r = k;
    else t[y].l = k;
    splay(k);
}
int find(int x, int k){
    int r = t[t[x].l].sz + 1;
    if ( r == k ) return t[x].v;
    if ( r < k ) return find(t[x].r, k-r);
    return find(t[x].l, k);
    /*x = root;
    while ( x ) {
        int r = t[t[x].l].sz + 1;
        if ( r == k ) return t[x].v;
        if ( r < k ) k-=r, x=t[x].r;
        else x=t[x].l;
    }
    return -1;*/
}
int adjust(int d){
    int x = root, k = 0;
    while ( x ) {
        if ( t[x].v < d ) k = x, x = t[x].r;
        else x = t[x].l;
    }
    if ( k != 0 ){
        splay(k);
        if ( t[k].v < d ){
            root = t[k].r;
            t[root].p = 0;
            return t[t[k].l].sz+1;
        }
    }
    return 0;
}
int main()
{
    //const char path[] = "D:\\Project\\AlgorithmExam\\test.txt";
    //freopen(path, "r+", stdin);
 
    int n, m, d0;
    while ( scanf("%d%d", &n, &d0) != EOF){
        t[0].l=t[0].r=t[0].v=t[0].p=t[0].sz=cnt = root = 0;
        char ch[5];
        int num = 0, ADD = 0;
        for ( int i = 0; i < n ; ++i ){
            scanf("%s%d", ch, &m);
            if ( ch[0] == 'I' ){
                if ( m >= d0 ) ins(m-ADD);
            } else if ( ch[0] == 'A' ){
                ADD += m;
            } else if ( ch[0] == 'S' ){
                ADD -= m;
                num += adjust( -ADD + d0 );
            } else if ( ch[0] == 'F' ){
                if ( !root || t[root].sz < m ) printf("-1\n");
                else {
                    printf("%d\n", find(root,t[root].sz-m+1)+ADD);
                }
            }
        }
        printf("%d\n", num);
    }
    return 0;
}

 

 也用跳表做了一遍, 关键在于分段维护每段的大小。对于第i层, 划分为(a0,a1](a1,a2]...(ak,an], 对任意节点ai, sz[ai] = #(区间(ai-1, ai])。

/**************************************************************
    Problem: 1503
    User: leezy
    Language: C++
    Result: Accepted
    Time:856 ms
    Memory:39492 kb
****************************************************************/
 
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <functional>
#define N 50015
#define M 1000000
#define INF 0x6fffffff
#define MAX_LEVEL 32
#define NIL (0)
#define min(a,b) ((a)<(b))?(a):(b)
struct SkipListNode{
    int key, sz;
    int prev, next, up, down;
} Node[N*MAX_LEVEL+N];
int List[MAX_LEVEL+1], Upd[MAX_LEVEL+1], tot[MAX_LEVEL+1], top, cnt;
void Dump(){
    int k = top;
    while ( k >= 0 ){
        printf("Level[%d]: ", k);
        int p = List[k--];
        while ( p != NIL ){
            if ( Node[p].key == -INF ) printf("-INF[%d]-->", Node[p].sz);
            else printf("%d[%d]-->", Node[p].key, Node[p].sz);
            p = Node[p].next;
        }
        printf("\n");
    }
}
void Init(int seed){
    top = -1;
    cnt = 0;
    Node[0].key = INF;
    Node[0].sz = 0x0fffffff;
    srand(seed);
}
int NewNode(int key){
    int cc = ++cnt;
    Node[cc].key = key;
    Node[cc].sz = 0;
    Node[cc].next = Node[cc].prev = Node[cc].up = Node[cc].down = NIL;
    return cc;
}
template<class Comp>
int Find(int key, const Comp& comp){
    if ( top < 0 ) return NIL;
    int k = top, p = List[top];
    tot[top+1] = 0;
    while ( k >= 0 ){
        tot[k] = tot[k+1];
        for (int q = Node[p].next; comp(Node[q].key, key); ){
            tot[k] += Node[q].sz;
            p = q, q = Node[p].next;
        }
        Upd[k--] = p;
        p = Node[p].down;
    }
    return (Node[Upd[0]].key == -INF)?(NIL):(tot[0]);
}
void Ins(int key){
    //printf("Ins\n");
    Find(key, std::less_equal<int>());
    int k = 0;
    for (float r = 0; r < 0.5 && k < MAX_LEVEL; r=((float)rand())/RAND_MAX) ++k;
    for (; top + 1 < k; ){
        int p = NewNode(-INF);
        if ( -1 == top ) List[++top] = p;
        else {
            int q = List[top];
            Node[q].up = p; Node[p].down = q;
            List[++top] = p;
        }
        tot[top] = 0; Upd[top] = p;
    }
    for (int i = 0, top2 = -1; i <= top; ++i ){
        int q = Node[Upd[i]].next;
        if ( i < k ){
            int p = NewNode(key);
            Node[p].sz = tot[0] - tot[i] + 1;
            Node[q].sz = Node[q].sz - Node[p].sz;
            Node[p].next = q; Node[q].prev = p;
            Node[Upd[i]].next = p; Node[p].prev = Upd[i];
            if ( -1 == top2 ) top2 = p;
            else {
                Node[top2].up = p; Node[p].down = top2;
                top2 = p;
            }
        }
        Node[q].sz += 1;
    }
    //Dump();
}
int Del(int key){
    //printf("Del\n");
    int r = Find(key, std::less<int>());
    if ( NIL != r ){
        for (int i = 0; i <= top; ++i){
            int p = List[i];
            int q = Node[Upd[i]].next;
            Node[q].sz = Node[q].sz - tot[0] + tot[i];
            Node[p].next = q; Node[q].prev = p;
        }
        for (; top >= 0 && Node[Node[List[top]].next].key == INF; ) --top;
        //Dump();
    }
    return r;
}
int Find_Kth(int k){
    if ( top < 0 ) return -1;
    int top2 = top, p = List[top];
    while ( top2 >= 0 ){
        for (int q = Node[p].next; Node[q].sz < k; p = q, q = Node[p].next) k -= Node[q].sz;
        Upd[ top2-- ] = p;
        p = Node[p].down;
    }
    return (Node[Node[Upd[0]].next].sz != k)?(-1):(Node[Node[Upd[0]].next].key);
}
int main()
{
    //const char path[] = "D:\\Project\\AlgorithmExam\\test.txt";
    //freopen(path, "r+", stdin);
 
    int n,m, num;
    while ( scanf("%d%d", &n, &m) != EOF ){
        Init(num+n+m);
        num = 0;
        int d = 0, v, t = 0;
        char op[5];
        for ( int i = 0; i < n; ++i ){
            scanf("%s%d", op, &v);
            if ( 'I' == op[0] ){
                if ( v >= m ) Ins(v-d), ++t;
            } else if ( 'A' == op[0] ){
                d += v;
            } else if ( 'S' == op[0] ){
                d -= v;
                num += Del(m-d);
            } else if ( 'F' == op[0] ){
                int dd = Find_Kth(t-num-v+1);
                if ( -1 == dd ) printf("-1\n");
                else printf("%d\n", dd+d);
            }
        }
        printf("%d\n", num);
    }
    return 0;
}
View Code

 

 

posted on 2013-11-18 07:58  leezyli  阅读(213)  评论(0编辑  收藏  举报

导航