• HihoCoder1329 平衡树·Splay(附STL版)


    输入

    第1行:1个正整数n,表示操作数量,100≤n≤200,000

    第2..n+1行:可能包含下面3种规则:

    1个字母'I',紧接着1个数字k,表示插入一个数字k到树中,1≤k≤1,000,000,000,保证每个k都不相同

    1个字母'Q',紧接着1个数字k。表示询问树中不超过k的最大数字

    1个字母'D',紧接着2个数字a,b,表示删除树中在区间[a,b]的数。

    输出

    若干行:每行1个整数,表示针对询问的回答,保证一定有合法的解

    样例输入
    6
    I 1
    I 2
    I 3
    Q 4
    D 2 2
    Q 2
    样例输出
    3
    1
     ps:

    学习了一周多的后缀自动机,暂时搁下,回去学习平衡树。

    离学习treap树已经有两周多了,终于开始学splay了,ORZ平衡树。

    一查维基百科,发现tarjan还参与发明了splay树,ORZ:“The splay tree was invented by Daniel Sleator and Robert Tarjan in 1985.

    ps:

    第一次写,也是抄的模板,加了自己的一些批注。

    也做了一点小改动,hihocoder在删去区间[a,b]的时候是先加上点a和b,防止没有这两个点。

    而此处的做法是找到最大的x<a,最小的y>b(不能等于!),然后删去x,y之间的,这样就不必加点了。

    不过Find(x)函数可以判断是否存在某点,但移到根的不一定是x。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxN=400101;
    const int inf=2147483647;
    struct SplayData
    {
        int fa,ch[2],key,cnt,size;//cnt是单个节点的数据;size是子树的数据 ,此题不用size; 
        SplayData()//自动初始每一个新建data 
        {
            ch[0]=ch[1]=0;
            cnt=0;
            size=0;
        }
    };
    
    struct SplayTree
    {
        int cnt;
        int root;
        SplayData S[maxN];
        SplayTree()//自动初始树 
        {
            root=0;
            cnt=0;
            Insert(-inf);//插入极大极小值 
            Insert(inf);
        }
        void Insert(int x)
        {
            int now=root;//root不一定为0 ; 
            int nowfa=0;//上一个now,fa[now]; 
            while (now!=0&&S[now].key!=x){
                nowfa=now;
                now=S[now].ch[x>S[now].key];
            } 
            if (now==0){//节点为空 ,新建节点; 
                cnt++;
                now=cnt;
                S[cnt].fa=nowfa;//父关系 
                S[cnt].cnt=S[cnt].size=1;
                S[cnt].key=x;
                if (nowfa!=0)   S[nowfa].ch[x>S[nowfa].key]=cnt;//子关系 
                if (root==0)    root=1;//树非空 
            }
            else S[now].cnt++;//节点非空 
            Splay(now,0);
            return;
        }
        bool Find(int x)
        {
            if (root==0)  return 0;//树为空,肯定找不到
            int now=root;
            while ((S[now].ch[x>S[now].key]!=0)&&(x!=S[now].key)) now=S[now].ch[x>S[now].key];
            //nice code!!! 
            Splay(now,0);//不管找到没都把now移到根节点。 
            if (x!=S[now].key)  return 0;
            return 1;
        }
        void Rotate(int x)
        {
            int y=S[x].fa;
            int z=S[y].fa;
            int k1=S[y].ch[1]==x;
            int k2=S[z].ch[1]==y;
            S[z].ch[k2]=x;
            S[x].fa=z;
            S[y].ch[k1]=S[x].ch[k1^1];
            S[S[x].ch[k1^1]].fa=y;
            S[x].ch[k1^1]=y;
            S[y].fa=x;
            return;
        }
        void Splay(const int x,int goal)
        {
            while (S[x].fa!=goal)
            {
                int y=S[x].fa;
                int z=S[y].fa;
                if (z!=goal)
                    ((S[z].ch[0]==y)^(S[y].ch[0]==x))?Rotate(x):Rotate(y);//异则x,同则y 
                Rotate(x);
            }
            if (goal==0)
                root=x;
            return;
        }
        int Next(int x,int opt)
        {
            Find(x);//先移‘x’到根 
            int now=root;
            if ((S[now].key<x)&&(opt==0)) return now; //对根做处理
            if ((S[now].key>x)&&(opt==1)) return now;
            now=S[now].ch[opt];
            while (S[now].ch[opt^1]!=0)   now=S[now].ch[opt^1];//沿子树一直找
            return now;
        }
        void DeleteRange(int l,int r)
        {
           // Insert(l);//删去
           ?//Insert(r);
            int prep=Next(l,0);//移到根
            int nex=Next(r,1);//移到根的右儿子 
            Splay(prep,0);
            Splay(nex,prep);
            S[nex].ch[0]=0;//删去根的右儿子的左儿子 
            return;
        }
    };
    SplayTree SP;
    int main()
    {
        int k,l,r,n; 
        scanf("%d",&n);
        for (int i=1;i<=n;i++){
            char opt[2];
            scanf("%s",opt);
            if (opt[0]=='I'){
                scanf("%d",&k);
                SP.Insert(k);
            }
            else if (opt[0]=='Q'){ 
                scanf("%d",&k);
                if (SP.Find(k)){//恰好找到 
                    printf("%d
    ",k);
                    continue;
                }
                int prep=SP.Next(k,0);//否则 ,找左子树最大。 
                printf("%d
    ",SP.S[prep].key);
            }
            else if (opt[0]=='D'){
                scanf("%d%d",&l,&r);
                SP.DeleteRange(l,r);
            }
        }
        return 0;
    }

    像这样没有特殊的处理的,基于同样原理的set还是可以乱搞的。 

     

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<set>
    using namespace std;
    set<int>q;
    int main()
    {
        int n,i,a,b;
        char opt[3];
        scanf("%d",&n);
        while(n--){
            scanf("%s",opt);
            if(opt[0]=='I'){
                scanf("%d",&a);
                q.insert(a);
            }
            else if(opt[0]=='Q'){
                scanf("%d",&a);
                set<int>:: iterator it=q.upper_bound(a);
                it--;
                printf("%d
    ",*it);
            }
            else {
                scanf("%d%d",&a,&b);
                q.erase(q.lower_bound(a),q.upper_bound(b));
            }
        }
        return 0;
    }
  • 相关阅读:
    电信10兆指的是多少Mbps
    keycloak ssl-required报错问题处理
    Centos7 DNS神奇的配置
    angular4套用primeng样式
    Python库大全
    jquery根据name属性的高级选择
    Js String 属性扩展
    SQLSever 触发器
    IaaS, PaaS和SaaS
    Sql Server 基础知识
  • 原文地址:https://www.cnblogs.com/hua-dong/p/7898287.html
Copyright © 2020-2023  润新知