hiho #1329 : 平衡树·Splay

#1329 : 平衡树·Splay

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB
描述

小Ho:小Hi,上一次你跟我讲了Treap,我也实现了。但是我遇到了一个关键的问题。

小Hi:怎么了?

小Ho:小Hi你也知道,我平时运气不太好。所以这也反映到了我写的Treap上。

小Hi:你是说你随机出来的权值不太好,从而导致结果很差么?

小Ho:就是这样,明明一样的代码,我的Treap运行结果总是不如别人。小Hi,有没有那种没有随机因素的平衡树呢?

小Hi:当然有了,这次我就跟你讲讲一种叫做Splay的树吧。而且Splay树能做到的功能比Treap要更强大哦。

小Ho:那太好了,你快告诉我吧!

提示:Splay

输入

第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

不会就套板子;

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pi (4*atan(1.0))
#define eps 1e-14
const int N=1e5+10,MAXN=1e6+10,inf=2147483647;
const ll INF=1e18+10,mod=2147493647;
int cnt, rt;
int Add[MAXN];
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)return 0;
    if(T[rt].num>1) return rt;
    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 key) //删除值为key的节点1个
{
    int x=Find(key);
    if(!x) return;
    if(T[x].num>1)
    {
        T[x].num--;
        PushUp(x);
        return;
    }
    int y=T[x].son[0];
    while(T[y].son[1])
        y=T[y].son[1];
    int z=T[x].son[1];
    while(T[z].son[0])
        z=T[z].son[0];
    if(!y && !z)
    {
        rt=0;
        return;
    }
    if(!y)
    {
        Splay(z, 0);
        T[z].son[0]=0;
        PushUp(z);
        return;
    }
    if(!z)
    {
        Splay(y, 0);
        T[y].son[1]=0;
        PushUp(y);
        return;
    }
    Splay(y, 0);
    Splay(z, y);
    T[z].son[0]=0;
    PushUp(z);
    PushUp(y);
}

int GetRank(int key) //获得值<=key的节点个数
{
    if(!Find(key))
    {
        Insert(key);
        int tmp=T[T[rt].son[0]].size;
        Delete(key);
        return tmp;
    }
    else
        return T[T[rt].son[0]].size+T[rt].num;
}

void Delete(int l, int r) //删除值在[l, r]中的所有节点 l!=r
{
    if(l>r)return;
    if(!Find(l)) Insert(l);
    int p=Prev();
    if(!Find(r)) Insert(r);
    int q=Succ();
    if(!p && !q)
    {
        rt=0;
        return;
    }
    if(!p)
    {
        T[rt].son[0]=0;
        PushUp(rt);
        return;
    }
    if(!q)
    {
        Splay(p, 0);
        T[rt].son[1]=0;
        PushUp(rt);
        return;
    }
    Splay(p, q);
    T[p].son[1]=0;
    PushUp(p);
    PushUp(q);
}
char str[N];
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        int l,r;
        scanf("%s%d",str,&l);
        if(str[0]=='I')
            Insert(l);
        else if(str[0]=='Q')
        {
            Insert(l);
            printf("%d\n",T[Prev()].key);
            Delete(l);
        }
        else
        {
            scanf("%d",&r);
            Delete(l,r);
        }
    }
    return 0;
}

 

#1329 : 平衡树·Splay

时间限制: 10000ms
单点时限: 1000ms
内存限制: 256MB
描述

小Ho:小Hi,上一次你跟我讲了Treap,我也实现了。但是我遇到了一个关键的问题。

小Hi:怎么了?

小Ho:小Hi你也知道,我平时运气不太好。所以这也反映到了我写的Treap上。

小Hi:你是说你随机出来的权值不太好,从而导致结果很差么?

小Ho:就是这样,明明一样的代码,我的Treap运行结果总是不如别人。小Hi,有没有那种没有随机因素的平衡树呢?

小Hi:当然有了,这次我就跟你讲讲一种叫做Splay的树吧。而且Splay树能做到的功能比Treap要更强大哦。

小Ho:那太好了,你快告诉我吧!

提示:Splay

输入

第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

转载于:https://www.cnblogs.com/jhz033/p/6248556.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值