NOI2004 郁闷的出纳员 splay

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

 抄别人模板过的...打了点注释算是大概懂了...

/********************* Template ************************/
#include <set>
#include <map>
#include <list>
#include <cmath>
#include <ctime>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <sstream>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
#define BUG         cout<<" BUG! "<<endl;
#define LINE        cout<<" ------------------ "<<endl;
#define FIN         freopen("in.txt","r",stdin);
#pragma comment     (linker,"/STACK:102400000,102400000")
template<class T> inline T L(T a)       {return (a << 1);}
template<class T> inline T R(T a)       {return (a << 1 | 1);}
template<class T> inline T lowbit(T a)  {return (a & -a);}
template<class T> inline T Mid(T a,T b) {return ((a + b) / 2);}
template<class T> inline T gcd(T a,T b) {return b ? gcd(b,a%b) : a;}
template<class T> inline T lcm(T a,T b) {return a / gcd(a,b) * b;}
template<class T> inline T Min(T a,T b) {return a < b ? a : b;}
template<class T> inline T Max(T a,T b) {return a > b ? a : b;}
template<class T> inline T Min(T a,T b,T c)     {return min(min(a,b),c);}
template<class T> inline T Max(T a,T b,T c)     {return max(max(a,b),c);}
template<class T> inline T Min(T a,T b,T c,T d) {return min(min(a,b),min(c,d));}
template<class T> inline T Max(T a,T b,T c,T d) {return max(max(a,b),max(c,d));}
template<class T> inline void mem(T &a,int b)   {memset(a,b,sizeof(a));}
template<class T> inline T exGCD(T a, T b, T &x, T &y){ //
    if(!b) return x = 1,y = 0,a;
    T res = exGCD(b,a%b,x,y),tmp = x;
    x = y,y = tmp - (a / b) * y;
    return res;
}
typedef long long LL;    typedef unsigned long long ULL;
//typedef __int64 LL;      typedef unsigned __int64 ULL;
const LL LINF   = 1LL << 60;
const int MOD   = 1000000007;
const int INF   = 0x7fffffff;
const int MAXN  = (int)1e5+5;
const double EPS    = 1e-8;
const double DINF   = 1e15;
const double PI     = acos(-1.0);

/*********************   By  F   *********************/
int n,lim,num,ans;
char op;
struct splay{
    int ch[MAXN][2];    // 0:左节点 1:右节点
    int pre[MAXN];      // 父节点
    int cnt[MAXN];
    int sz[MAXN];       // size[] 保存节点
    int val[MAXN];
    int root,top;
    int sum;
    inline void up(int x){
        sz[x] = cnt[x] + sz[ch[x][0]] + sz[ch[x][1]];
    }
    inline void Rotate(int x,int c){    //  0 左旋, 1 右旋
        int y = pre[x],z = pre[y];      //  y为x的父亲,z为y的父亲
        ch[y][!c] = ch[x][c];           //  举例-> 如果右旋:x的右节点 -> y的左节点
        pre[ch[x][c]] = y;              //  标记: x右节点的父亲 -> y
        pre[x] = z;                     //  y旋转到x下面 -> 标记: x的父节点 -> y的父节点
        if(z != 0)                      //  若y不是根节点,y的父节点转为x的父节点
            ch[z][ch[z][1] == y] = x;
        ch[x][c] = y;                   //  x的右节点已经给了y的左节点,所以x的右节点变为y
        pre[y] = x;                     //  y的父节点变为x
        up(y);                          //  ?
    }
    inline void Splay(int x,int goal){
        while(pre[x] != goal){
            if(pre[pre[x]] == goal) Rotate(x,ch[pre[x]][0] == x);   //  如果x的祖父是目标节点,只需要转一次
            else{
                int y = pre[x],z = pre[y],c = (ch[z][0] == y);
                if(ch[y][c] == x) Rotate(x,!c),Rotate(x,c);         //  z字旋转 x左右各转一次
                else Rotate(y,c),Rotate(x,c);                       //  1字旋转 先转y 后转x
            }
        }
        up(x);                          //  ?
        if(goal == 0) root = x;         //  0节点是根节点的父节点,如果要转到0下 则该点为根
    }
    inline void Init(){                 //  初始化
        ch[0][0] = ch[0][1] = pre[0] = sz[0] = cnt[0] = sum = root = top = 0;
    }
//    inline void RTO(int k,int goal){    //  将第k位数旋转到goal的下面
//        int x = root;
//        while(sz[ch[x][0]] != k-1){
//            if(k < sz[ch[x][0]]+1) x = ch[x][0];
//            else{
//                k -= (sz[ch[x][0]]+1);
//                x = ch[x][1];
//            }
//        }
//        Splay(x,goal);
//    }
    inline void Insert(int &x,int key,int f){
        if(!x){                         //  如果x是叶子节点
            x = ++top;                  //  节点标号,从1开始
            ch[x][0] = ch[x][1] = 0;    //  子节点设置0
            sz[x] = cnt[x] = 1;
            val[x] = key;
            pre[x] = f;
            Splay(x,0);                 //  将该点转到根
            return ;
        }
        if(key == val[x]){              //  如果权值重复
            cnt[x]++;                   //  cnt[x]++
            sz[x]++;                    //  size[x]++
            Splay(x,0);                 //  将该点转到根
            return ;
        }
        else if(key < val[x]) Insert(ch[x][0],key,x);   //  保证平衡树的性质
        else if(key > val[x]) Insert(ch[x][1],key,x);
        up(x);
    }
    inline void del(int &x,int f){
        if(!x) return ;                 //  如果x是叶子节点
        if(val[x] >= lim){              //  从x左边开始删
            del(ch[x][0],x);
        }else{
            sum += sz[ch[x][0]] + cnt[x];
            x = ch[x][1];
            pre[x] = f;
            if(f == 0) root = x;
            del(x,f);
        }
        if(x) up(x);
    }
    inline int find_kth(int x,int k){
        if(k < sz[ch[x][0]]+1) return find_kth(ch[x][0],k);
        else if(k > sz[ch[x][0] ] + cnt[x])
            return find_kth(ch[x][1],k-sz[ch[x][0]]-cnt[x]);
        else{
            Splay(x,0);
            return val[x];
        }
    }
    inline void show(int x){
        if(x){
            printf("%d: Left: %d Right: %d Val: %d Size: %d
",x,ch[x][0],ch[x][1],val[x],sz[x]);
            show(ch[x][0]);
            show(ch[x][1]);
        }
    }
}s;
int main(){
    while(~scanf("%d%d",&n,&lim)){
        s.Init();
        int limit = lim;
        for(int i = 0 ; i < n ; i++){
            getchar();
            scanf("%c %d",&op,&num);
            if(op == 'I'){
                if(num < limit) continue;
                s.Insert(s.root,num+lim-limit,0);   //  从根节点开始插入
            }
            if(op == 'A') lim -= num;
            if(op == 'S'){
                lim += num;
                if(s.sz[s.root] > 0) s.del(s.root,0);
            }
            if(op == 'F'){
                int sz = s.sz[s.root];
                if(num > sz) printf("-1
");
                else printf("%d
",s.find_kth(s.root,sz-num+1)-lim+limit);
            }
            //s.show(s.root);
        }
        printf("%d
",s.sum);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Felix-F/p/3325518.html