zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    [haoi2015]T1
    [haoi2014]走出金字塔
    [haoi2014]穿越封锁线
    [haoi2014]遥感监测
    [haoi2012]高速公路
    [haoi2012]容易题
    [haoi2008]排名系统
    【bzoj1014】[JSOI2008]火星人prefix
    0916解题报告
    生成树计数问题
  • 原文地址:https://www.cnblogs.com/Felix-F/p/3325518.html
Copyright © 2011-2022 走看看