平衡树——splay
#include<bits/stdc++.h>
using namespace std;
#define inf 0x7fffffff
int n;
int tot,root;//结点总数,根
struct jade
{
int val,fa,size,cnt;//权值,父亲,子树大小,重复次数
int son[2];//s[0] 表示左儿子,s[1] 表示右儿子。
}t[1000005];
void init(int x,int v,int father)//创建节点后对它进行初始化
{
t[x].cnt=t[x].size=1;
t[x].val=v;
t[x].fa=father;
return ;
}
void pushup(int x)//旋转后重新整合节点信息。
{
t[x].size=t[t[x].son[0]].size+t[t[x].son[1]].size+t[x].cnt;
return ;
}
void rotate(int x)
{
int y=t[x].fa;
int z=t[y].fa;
bool k=(t[y].son[1]==x);//k==0:x为y的左儿子 k==1:x为y的右儿子
t[z].son[t[z].son[1]==y]=x;//x代替y的位置成为z的儿子
t[x].fa=z;//x的父亲变为z
t[y].son[k]=t[x].son[k^1];//若 x为y的左儿子,则x的右儿子代替x的位置成为y的左儿子
//若 x为y的右儿子,则x的左儿子代替x的位置成为y的右儿子
t[t[x].son[k^1]].fa=y;//代替x的位置的儿子的父亲是y
t[x].son[k^1]=y;//y代替了x的儿子(那个代替了x的位置的儿子
t[y].fa=x;//y为x的儿子
pushup(y);
pushup(x);//仿照线段树,整合应当先下后上,所以我们先 pushup(y),后 pushup(x)。(旋转后y在x下方)
return ;
}
void splay(int x,int k)
{
while(t[x].fa!=k)//只要还没有到 k 下方就不结束
{
int y=t[x].fa;
int z=t[y].fa;
if(z!=k)
{
if((t[y].son[1]==x)^(t[z].son[1]==y))
{
rotate(x);
}
else
{
rotate(y);
}
}
rotate(x);
}
if(k==0)
{
root=x;
}
return ;
}
void pre(int v)//查找数字v对应的点号
{
//找到v在树中的位置,并将它旋转到根
int x=root;
if(x==0)
{
return ;
}
while(t[x].val!=v&&t[x].son[v>t[x].val]!=0)//大于x的权值就走右子树,否则走左子树,直到 x的权值即为v或我们要走的子树为空时停止
{
x=t[x].son[v>t[x].val];
}
splay(x,0);
return ;
}
void add(int v)
{
int x=root;
int fa=0;
while(x!=0&&t[x].val!=v)//用查找过程找到要插入的位置,进行插入,随后将新元素旋转到根
{
fa=x;
x=t[x].son[v>t[x].val];
}
//插入一段序列到y后,假设y的后继是z,我们会先将y旋转到根,然后再 splay(z,y) 此时只需将序列插入z的左子树即可
if(x!=0)//这说明 v 已经在树中出现过。
{
t[x].cnt++;
}
else//新建结点。
{
tot++;
x=tot;
init(x,v,fa);//初始化。
if(fa!=0)//u 不在根的位置上。
{
t[fa].son[v>t[fa].val]=x;
}
}
splay(x,0);
return ;
}
int get_k(int v,bool find)//为 0 表示找前驱,为 1 表示找后继。
{
pre(v);
int x=root;//首先将给定结点转到根,然后观察权值间的关系
if(v<t[x].val&&find==1)//找后继时,根的权值大于给定值。
{
return x;
}
if(v>t[x].val&&find==0)//找前驱时,根的权值小于给定值。
{
return x;
}
x=t[x].son[find];
while(t[x].son[find^1]!=0)//此时 u 还有儿子,往下跳。
{
x=t[x].son[find^1];
}
splay(x,0);
return x;
}
void del(int v)
{
//首先在树中找到要删除的元素 ,将它转到根节点并删去,这样原来的树就分裂成了两棵树。接下来将左子树中拥有最大权值的那一个元素转到根,由于它是左子树中的最大元素,所以它不存在右儿子,这样只要把原来的右子树作为它的右子树,就重新合并成了一棵树。
int l=get_k(v,0);//查找前驱后缀时就已经转到根了,无需单独 splay。
int r=get_k(v,1);
splay(l,0);
splay(r,l);
if(t[t[r].son[0]].cnt>1)//有重复,减去重复次数即可。
{
t[t[r].son[0]].cnt--;
splay(t[r].son[0],0);
}
else
{
t[r].son[0]=0;//删除左儿子。
}
return ;
}
int read_k(int v)
{
pre(v);//转到根。
return t[t[root].son[0]].size;//左子树大小
//排名应为左子树大小加一。但由于哨兵的影响,左子树中还会有一个极小值,它让子树大小增加了一。因此直接返回 t[t[root].s[0]].size 即可。
}
int kth(int k)
{
int x=root;
if(t[x].size<k)
{
return -1;//整棵树都没有 k 个结点,无解。
}
while(1)
{
if(k>t[t[x].son[0]].size+t[x].cnt)//k 大于左子树大小,答案必然在右子树。
{
k-=t[t[x].son[0]].size+t[x].cnt;//更新 k
x=t[x].son[1];
}
else
{
if(t[t[x].son[0]].size>=k)//k 不大于左子树大小,答案在左子树。
{
x=t[x].son[0];
}
else//答案不在左子树也不在右子树,必然就是当前结点
{
splay(x,0);
return t[x].val;
}
}
}
return 0;
}
void work()
{
//1.插入 xx 数;
//2.删除 xx 数(若有多个相同的数,因只删除一个);
//3.查询 xx 数的排名(若有多个相同的数,因输出最小的排名);
//4.查询排名为 xx 的数;
//5.求 xx 的前趋(前趋定义为小于 xx,且最大的数);
//6.求 xx 的后继(后继定义为大于 xx,且最小的数)。
int opt,x;
cin>>opt>>x;
if(1==2)
{
}
else if(opt==1)
{
add(x);
}
else if(opt==2)
{
del(x);
}
else if(opt==3)
{
add(x);
cout<<read_k(x)<<endl;
del(x);
}
else if(opt==4)
{
cout<<kth(x+1)<<endl;
}
else if(opt==5)
{
cout<<t[get_k(x,0)].val<<endl;
}
else if(opt==6)
{
cout<<t[get_k(x,1)].val<<endl;
}
return ;
}
int main()
{
add(-inf);//插入哨兵
add(inf);
cin>>n;
while(n--)
{
work();
}
return 0;
}
D3906-ourstar的spaly
樱雪喵的spaly
XichenOC的spaly
#include<bits/stdc++.h>
using namespace std;
struct jade
{
int son[2],size,fa,val,tag,cnt;
}t[100010];
int root,tot;
int inf=100000089;
int a[100010];
void pushup(int x)
{
if(x)
{
t[x].size=t[x].cnt+t[t[x].son[0]].size+t[t[x].son[1]].size;
}
return ;
}
void pushdown(int x)
{
if(x&&t[x].tag)
{
t[t[x].son[1]].tag^=1;
t[t[x].son[0]].tag^=1;
swap(t[x].son[1],t[x].son[0]);
t[x].tag=0;
}
}
void rotate(int x)
{
int y=t[x].fa;
int z=t[y].fa;
pushdown(x);
pushdown(y);
bool k=(t[y].son[1]==x);
t[z].son[t[z].son[1]==y]=x;
t[x].fa=z;
t[y].son[k]=t[x].son[k^1];
t[t[x].son[k^1]].fa=y;
t[x].son[k^1]=y;
t[y].fa=x;
pushup(y);
pushup(x);
return ;
}
void splay(int x,int k)
{
for(int i;(i=t[x].fa)!=k;rotate(x))
{
if(t[i].fa!=k)
{
if((t[t[x].fa].son[1]==x)^(t[t[i].fa].son[1]==i))
{
rotate(x);
}
else
{
rotate(i);
}
}
}
if(k==0)
{
root=x;
}
}
int build_tree(int l,int r,int fa)
{
if(l>r)
{
return 0;
}
int mid=(l+r)>>1;
tot++;
int x=tot;
t[x].fa=fa;
t[x].son[0]=t[x].son[1]=0;
t[x].cnt++;
t[x].val=a[mid];
t[x].size++;
t[x].son[0]=build_tree(l,mid-1,x);
t[x].son[1]=build_tree(mid+1,r,x);
pushup(x);
return x;
}
int find(int x)
{
int y=root;
while(1)
{
pushdown(y);
if(x>t[t[y].son[0]].size)
{
x-=t[t[y].son[0]].size+1;
if(!x)
{
return y;
}
y=t[y].son[1];
}
else
{
y=t[y].son[0];
}
}
}
void reverse(int x,int y)
{
int l=x-1,r=y+1;
l=find(l),r=find(r);
splay(l,0);
splay(r,l);
int pos=t[root].son[1];
pos=t[pos].son[0];
t[pos].tag^=1;
}
void dfs(int x)
{
pushdown(x);
if(t[x].son[0])
{
dfs(t[x].son[0]);
}
if(t[x].val!=-inf&&t[x].val!=inf)
{
cout<<t[x].val<<" ";
}
if(t[x].son[1])
{
dfs(t[x].son[1]);
}
}
int main()
{
int n,m,x,y;
cin>>n>>m;
a[1]=-inf;
a[n+2]=inf;
for(int i=1;i<=n;i++)
{
a[i+1]=i;
}
root=build_tree(1,n+2,0);
for(int i=1;i<=m;i++)
{
cin>>x>>y;
reverse(x+1,y+1);
}
dfs(root);
return 0;
}
以下是签名
${\scr {jade }}$ ${\scr {seek }}$
本文来自博客园,作者:BIxuan—玉寻,转载请注明原文链接:https://www.cnblogs.com/zhangyuxun100219/p/18977572

浙公网安备 33010602011771号