Live2d Test Env

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\n",k);
                continue;
            }
            int prep=SP.Next(k,0);//否则 ,找左子树最大。 
            printf("%d\n",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\n",*it);
        }
        else {
            scanf("%d%d",&a,&b);
            q.erase(q.lower_bound(a),q.upper_bound(b));
        }
    }
    return 0;
}

 

posted @ 2017-11-26 13:31  nimphy  阅读(226)  评论(0编辑  收藏  举报