bzoj3224普通平衡树 Splay

来源:互联网 发布:阿里云域名备案 编辑:程序博客网 时间:2024/05/08 13:40

第一次写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<<30using 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
原创粉丝点击