bzoj3224普通平衡树 Splay

2 篇文章 0 订阅
2 篇文章 0 订阅

第一次写Splay 憋了一天累觉不爱
网上关于Splay的资料太少了- -||
http://www.cnblogs.com/kuangbin/archive/2013/04/21/3034081.html
先贴 有空填坑
Splay的基本操作是rotate 左旋右旋
基于此的是splay 将一个点旋转到根节点 也正是因此(?) 它的复杂度均摊logn
insert操作 从根往下找知道找到叶子节点 插入 splay到根
delete操作 方法众多? 将它的前一名splay到根 它的后一名splay到根的右节点 它就在根的右节点的左节点 这也是提取一断区间的方法
split(a,k) 将第k名旋转到跟 右侧断开
merge(s1,s2) 将s1中最大元素旋转到根 根的右子树=s2
merge可以理解为两个序列的合并 两个序列的权值并不满足平衡树 或者根本不存在权值 我们是假设有那么一个权值 即代表它在序列里的位置 平衡树的中序遍历就是这个序列
区间操作:懒标记
和线段树大同小异 提取区间[a,b]:将a-1旋转到根 b+1旋转到根的右节点
区间反转:懒标记

#include<iostream>
#include<cstdio>
#define N 100005
#define inf 1<<30
using namespace std;
struct Node{int ls,rs,fa,sz,val;}t[N];
int n,num=0,root=0;
void upd(int k){t[k].sz=t[t[k].ls].sz+t[t[k].rs].sz+1;}
void rot(int x,int d){
    int y=t[x].fa,z=t[y].fa;
    if(d==1){
        t[y].ls=t[x].rs;t[t[x].rs].fa=y;
        t[x].rs=y;t[y].fa=x;
        t[x].fa=z;
        if(t[z].ls==y) t[z].ls=x;
        if(t[z].rs==y) t[z].rs=x;
        upd(y);upd(x);
    }
    if(d==0){
        t[y].rs=t[x].ls;t[t[x].ls].fa=y;
        t[x].ls=y;t[y].fa=x;
        t[x].fa=z;
        if(t[z].rs==y) t[z].rs=x;
        if(t[z].ls==y) t[z].ls=x;
        upd(y);upd(x);
    }
}
void splay(int x,int f){
    while(t[x].fa!=f){
        int y=t[x].fa,z=t[y].fa;
        if(z==f&&t[y].ls==x) rot(x,1);
        else if(z==f&&t[y].rs==x) rot(x,0);
        else if(t[z].ls==y&&t[y].ls==x) rot(y,1),rot(x,1);
        else if(t[z].rs==y&&t[y].rs==x) rot(y,0),rot(x,0);
        else if(t[z].ls==y&&t[y].rs==x) rot(x,0),rot(x,1);
        else if(t[z].rs==y&&t[y].ls==x) rot(x,1),rot(x,0);
    }
}
void newnode(int x){t[++num].sz=1;t[num].val=x;}
int Rank(int x,int k){
    int tmp=inf,ans=0;
    while(k){
        if(t[k].val==x) tmp=min(tmp,ans+t[t[k].ls].sz+1);
        if(t[k].val<x) ans+=t[t[k].ls].sz+1,k=t[k].rs;
        else k=t[k].ls;
    }
    return tmp==inf?ans:tmp;
}
int xth(int x,int k){
    while(1){
        if(t[t[k].ls].sz==x-1) return t[k].val;
        if(t[t[k].ls].sz<x-1) x-=(t[t[k].ls].sz+1),k=t[k].rs;
        else k=t[k].ls;
    }
}
int pre(int x,int k){
    int ans=-inf;
    while(k){
        if(t[k].val<x) ans=max(ans,t[k].val),k=t[k].rs;
        else k=t[k].ls;
    }
    return ans;
}
int suc(int x,int k){
    int ans=inf;
    while(k){
        if(t[k].val>x) ans=min(ans,t[k].val),k=t[k].ls;
        else k=t[k].rs;
    }
    return ans;
}
void ins(int x,int k){
    if(t[k].val<x){
        if(t[k].rs==0) newnode(x),t[k].rs=num,t[num].fa=k,splay(num,0),root=num;
        else ins(x,t[k].rs),upd(k);
    }
    else{
        if(t[k].ls==0) newnode(x),t[k].ls=num,t[num].fa=k,splay(num,0),root=num;
        else ins(x,t[k].ls),upd(k);
    }
}
int getk(int now,int k){
    int wtf=t[t[now].ls].sz+1;
    if(wtf==k) return now;
    if(wtf<k) return getk(t[now].rs,k-wtf);
    else return getk(t[now].ls,k);
}
void del(int x){
    int k=Rank(x,root);
    int n1=getk(root,k-1);
    splay(n1,0);root=n1;
    splay(getk(root,k+1),root);
    t[t[root].rs].ls=0;
}
int main(){
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    scanf("%d",&n);
    ins(-inf,root);
    ins(inf,root);
    while(n--){
        int opt,x;
        scanf("%d%d",&opt,&x);
        if(opt==1) ins(x,root);
        if(opt==2) del(x);
        if(opt==3) printf("%d\n",Rank(x,root)-1);
        if(opt==4) printf("%d\n",xth(x+1,root));
        if(opt==5) printf("%d\n",pre(x,root));
        if(opt==6) printf("%d\n",suc(x,root));
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值