NOI2004 郁闷的出纳员

往事不堪回首。。

这个题目花了2天时间才A了。

思路照搬SnowyJone大牛:http://www.cnblogs.com/w007878/p/3453023.html  Orz。。

此处可找到数据:http://tieba.baidu.com/p/1217076472

真是虐心的两天,整个人都瘦了。。

当然也算值了,为的就是splay的模板大计!

操作中较为难办的就是相同数和删除区间。

相同数解决方法:保证每个数都不同,用num记录其个数

删除区间[l, r]:实际上是将l的前驱p,r的后继q,将p移动到q的子节点,直接删除p的右子树,然后更新即可。相比对序列操作的l 和 r可能不存在,需要特殊处理一下。

再者就是各种细节:

  1. 初始工资小于MIN的不算踢出的。。

  2. 各种PUSHUP,PUSHDOWN注意。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cmath>
#include <utility>
#include <vector>
#include <queue>
#include <map>
#include <set>
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)>(y)?(y):(x))
#define INF 0x3f3f3f3f
#define MAXN 100005

using namespace std;

int cnt, rt;
int Add[MAXN],ans;

struct Tree{
    int key, num, size, fa, son[2];
}T[MAXN];

inline void PushUp(int x)
{
    T[x].size=T[T[x].son[0]].size+T[T[x].son[1]].size+T[x].num;
}

inline void PushDown(int x)
{
    if(Add[x])
    {
        if(T[x].son[0])
        {
            T[T[x].son[0]].key+=Add[x];
            Add[T[x].son[0]]+=Add[x];
        }
        if(T[x].son[1])
        {
            T[T[x].son[1]].key+=Add[x];
            Add[T[x].son[1]]+=Add[x];
        }
        Add[x]=0;
    }
}

inline int Newnode(int key, int fa) //新建一个节点并返回
{
    ++cnt;
    T[cnt].key=key;
    T[cnt].num=T[cnt].size=1;
    T[cnt].fa=fa;
    T[cnt].son[0]=T[cnt].son[1]=0;
    return cnt;
}

inline void Rotate(int x, int p) //0左旋 1右旋
{
    int y=T[x].fa;
    PushDown(y);
    PushDown(x);
    T[y].son[!p]=T[x].son[p];
    T[T[x].son[p]].fa=y;
    T[x].fa=T[y].fa;
    if(T[x].fa)
        T[T[x].fa].son[T[T[x].fa].son[1] == y]=x;
    T[x].son[p]=y;
    T[y].fa=x;
    PushUp(y);
    PushUp(x);
}

void Splay(int x, int To) //将x节点移动到To的子节点中
{
    while(T[x].fa != To)
    {
        if(T[T[x].fa].fa == To)
            Rotate(x, T[T[x].fa].son[0] == x);
        else
        {
            int y=T[x].fa, z=T[y].fa;
            int p=(T[z].son[0] == y);
            if(T[y].son[p] == x)
                Rotate(x, !p), Rotate(x, p); //之字旋
            else
                Rotate(y, p), Rotate(x, p); //一字旋
        }
    }
    if(To == 0) rt=x;
}

int GetPth(int p, int To) //返回第p小的节点 并移动到To的子节点中
{
    if(!rt || p > T[rt].size) return 0;
    int x=rt;
    while(x)
    {
        PushDown(x);
        if(p >= T[T[x].son[0]].size+1 && p <= T[T[x].son[0]].size+T[x].num)
            break;
        if(p > T[T[x].son[0]].size+T[x].num)
        {
            p-=T[T[x].son[0]].size+T[x].num;
            x=T[x].son[1];
        }
        else
            x=T[x].son[0];
    }
    Splay(x, 0);
    return x;
}

int Find(int key) //返回值为key的节点 若无返回0 若有将其转移到根处
{
    if(!rt) return 0;
    int x=rt;
    while(x)
    {
        PushDown(x);
        if(T[x].key == key) break;
        x=T[x].son[key > T[x].key];
    }
    if(x) Splay(x, 0);
    return x;
}

int Prev() //返回根节点的前驱 非重点
{
    if(!rt || !T[rt].son[0]) return 0;
    int x=T[rt].son[0];
    while(T[x].son[1])
    {
        PushDown(x);
        x=T[x].son[1];
    }
    Splay(x, 0);
    return x;
}

int Succ() //返回根结点的后继 非重点
{
    if(!rt || !T[rt].son[1]) return 0;
    int x=T[rt].son[1];
    while(T[x].son[0])
    {
        PushDown(x);
        x=T[x].son[0];
    }
    Splay(x, 0);
    return x;
}

void Insert(int key) //插入key值
{
    if(!rt)
        rt=Newnode(key, 0);
    else
    {
        int x=rt, y=0;
        while(x)
        {
            PushDown(x);
            y=x;
            if(T[x].key == key)
            {
                T[x].num++;
                T[x].size++;
                break;
            }
            T[x].size++;
            x=T[x].son[key > T[x].key];
        }
        if(!x)
            x=T[y].son[key > T[y].key]=Newnode(key, y);
        Splay(x, 0);
    }
}

void Delete(int l, int r) //删除值在[l, r]中的节点
{
    if(!Find(l)) Insert(l), ans--;
    int p=Prev();
    if(!Find(r)) Insert(r), ans--;
    int q=Succ();
    if(!p && !q)
    {
        ans+=T[rt].size;
        rt=0;
        return;
    }
    if(!p)
    {
        ans+=T[T[rt].son[0]].size;
        T[rt].son[0]=0;
        PushUp(rt);
        return;
    }
    if(!q)
    {
        Splay(p, 0);
        ans+=T[T[rt].son[1]].size;
        T[rt].son[1]=0;
        PushUp(rt);
        return;
    }
    Splay(p, q);
    if(T[p].son[1])
        ans+=T[T[p].son[1]].size;
    T[p].son[1]=0;
    PushUp(p);
    PushUp(q);
}

int N, MIN, k;
char ch;
int main()
{
    scanf("%d %d", &N, &MIN);
    while(N--)
    {
        scanf(" %c %d", &ch, &k);
        switch (ch)
        {
            case 'I':
                if(k >= MIN)
                    Insert(k);
                break;
            case 'A':
                T[rt].key+=k;
                Add[rt]+=k;
                break;
            case 'S':
                T[rt].key-=k;
                Add[rt]-=k;
                Delete(-INF, MIN-1);
                break;
            case 'F':
                if(T[rt].size-k+1>0)
                    printf("%d
", T[GetPth(T[rt].size-k+1, 0)].key);
                else
                    printf("-1
");
        }
    }
    printf("%d
", ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/Mathics/p/3978047.html