spaly插入删除查找,前缀后缀模板
题目链接普通平衡树
#include
#include
#include
using namespace std;
#define N 300005
int n,opt,x,root,sz;
int f[N],ch[N][2],key[N],size[N],cnt[N];
void clear(int x)
{
f[x]=ch[x][0]=ch[x][1]=key[x]=size[x]=cnt[x]=0;
}
int get(int x)
{
return ch[f[x]][1]==x;
}
void update(int x)
{
size[x]=cnt[x]+size[ch[x][0]]+size[ch[x][1]];
}
void rotate(int x)
{
int old=f[x],oldf=f[old],wh=get(x);
ch[old][wh]=ch[x][wh^1];
if (ch[old][wh]) f[ch[old][wh]]=old;
ch[x][wh^1]=old;
f[old]=x;
if (oldf) ch[oldf][ch[oldf][1]==old]=x;
f[x]=oldf;
update(old);
update(x);
}
void splay(int x)
{
for (int fa;fa=f[x];rotate(x))
if (f[fa])
rotate( (get(x)==get(fa))?fa:x );
root=x;
}
void insert(int x)
{
if (!root)
{
root=++sz;
cnt[sz]=size[sz]=1;key[sz]=x;
return;
}
int now=root,fa=0;
while (1)
{
if (x==key[now])
{
cnt[now]++;
update(now);
splay(now);
break;
}
fa=now;
now=ch[now][x>key[now]];
if (!now)
{
++sz;
f[sz]=fa;ch[fa][x>key[fa]]=sz;
size[sz]=cnt[sz]=1;
key[sz]=x;
update(fa);
splay(sz);
break;
}
}
}
int find(int x)
{
int now=root,ans=0;
while (1)
{
if (x1)
{
--cnt[root];
update(root);
return;
}
if (!ch[root][0]&&!ch[root][1])
{
clear(root);
root=0;
return;
}
if (!ch[root][0])
{
int oldroot=root;
root=ch[oldroot][1];
f[root]=0;
clear(oldroot);
return;
}
if (!ch[root][1])
{
int oldroot=root;
root=ch[oldroot][0];
f[root]=0;
clear(oldroot);
return;
}
int oldroot=root;
int leftbig=pre();splay(leftbig);
ch[root][1]=ch[oldroot][1];
f[ch[root][1]]=root;
clear(oldroot);
update(root);
return;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;++i)
{
scanf("%d%d",&opt,&x);
switch(opt)
{
case 1:
{
insert(x);
break;
}
case 2:
{
del(x);
break;
}
case 3:
{
int ans=find(x);
printf("%d\n",ans);
break;
}
case 4:
{
int ans=findx(x);
printf("%d\n",ans);
break;
}
case 5:
{
insert(x);
printf("%d\n",key[pre()]);
del(x);
break;
}
case 6:
{
insert(x);
printf("%d\n",key[nxt()]);
del(x);
break;
}
}
}
return 0;
}
splay区间翻转模板
#include
#include
#include
using namespace std;
#define N 100005
#define inf 1000000000
int n,m,l,r,root;
int a[N],f[N],ch[N][2],size[N],key[N],delta[N];
int get(int x)
{
return ch[f[x]][1]==x;
}
void update(int x)
{
size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
}
void pushdown(int x)
{
if (x&&delta[x])
{
delta[ch[x][0]]^=1;
delta[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
delta[x]=0;
}
}
int build(int l,int r,int fa)
{
if (l>r) return 0;
int mid=(l+r)>>1;
f[mid]=fa;key[mid]=a[mid];size[mid]=1;
int lch=build(l,mid-1,mid);
int rch=build(mid+1,r,mid);
ch[mid][0]=lch,ch[mid][1]=rch;
update(mid);
return mid;
}
void rotate(int x)
{
pushdown(f[x]);
pushdown(x);
int old=f[x],oldf=f[old],wh=get(x);
ch[old][wh]=ch[x][wh^1];
if (ch[old][wh]) f[ch[old][wh]]=old;
ch[x][wh^1]=old;
f[old]=x;
if (oldf) ch[oldf][ch[oldf][1]==old]=x;
f[x]=oldf;
update(old);
update(x);
}
void splay(int x,int tar)
{
for (int fa;(fa=f[x])!=tar;rotate(x))
if (f[fa]!=tar)
rotate( (get(x)==get(fa))?fa:x );
if (!tar) root=x;
}
int find(int x)
{
int now=root;
while (1)
{
pushdown(now);
if (x<=size[ch[now][0]]) now=ch[now][0];
else
{
x-=size[ch[now][0]];
if (x==1) return now;
x-=1;
now=ch[now][1];
}
}
}
void write(int x)
{
pushdown(x);
if (ch[x][0]) write(ch[x][0]);
if (key[x]!=-inf&&key[x]!=inf) printf("%d ",key[x]);
if (ch[x][1]) write(ch[x][1]);
}
int main()
{
scanf("%d%d",&n,&m);
a[1]=-inf;a[n+2]=inf;
for (int i=1;i<=n;++i) a[i+1]=i;
root=build(1,n+2,0);
for (int i=1;i<=m;++i)
{
scanf("%d%d",&l,&r);
if (l>=r) continue;
int aa=find(l);
int bb=find(r+2);
splay(aa,0);
splay(bb,aa);
delta[ch[ch[root][1]][0]]^=1;
}
write(root);
return 0;
}
自己加的注释
#include
#include
#include
#include
using namespace std;
int fa[maxn];//i的父节点
int ch[maxn][2];//左右儿子
int key[i];//结点i的数字
int cnt[i];//结点i的关键的权值
int size[maxn];//子树的大小
int sz;//整颗树的大小
int root;
inline void clear(int x)//删除之后把当前的各项值清为0
{
ch[x][0]=ch[x][1]=f[x]=cnt[x]=key[x]=size[x]=0;
}
inline int get(int x)//判断当前点的是父节点的左儿子还是右儿子
{
return ch[f[x]][1]==x;
}
inline void update(int x)//删除之后更新当前点的sz值
{
if (x)
{
size[x]=cnt[x];
if (ch[x][0]) size[x]+=size[ch[x][0]];
if (ch[x][1]) size[x]+=size[ch[x][1]];
}
}
inline void rotate(int x)
{
int old=f[x],oldf=f[old],which=get(x);
ch[old][which]=ch[x][which^1];//父节点的which儿子改为x的与which相反的儿子
f[ch[old][which]]=old;//把刚刚改的儿子的父亲改成old
f[old]=x;//把父节点的父亲改为x
ch[x][which^1]=old;//x的反儿子改为x
f[x]=oldf;//修改x的父亲
if (oldf)
ch[oldf][ch[oldf][1]==old]=x;//oldf的儿子改成x,位置和old一样
update(old);update(x);
}
inline void splay(int x)
{
for (int fa;(fa=f[x]);rotate(x))//一直rotate到根结点
if (f[fa])
rotate((get(x)==get(fa)?fa:x));//判断是否三点一线 若是先rotate X的父亲,否则rotate X
root=x;
}
inline void insert(int v)
{
//空树直接插
if (root==0) {sz++;ch[sz][0]=ch[sz][1]=f[sz]=0;key[sz]=v;cnt[sz]=1;size[sz]=1;root=sz;return;}
int now=root,fa=0;
while (1)
{
if (key[now]==v)
{
cnt[now]++;update(now);update(fa);splay(now);break;
}
fa=now;
now=ch[now][key[now]1) {cnt[root]--;return;}
//Only One Point
if (!ch[root][0]&&!ch[root][1]) {clear(root);root=0;return;}
//Only One Child
if (!ch[root][0])
{
int oldroot=root;root=ch[root][1];f[root]=0;clear(oldroot);return;
}
else if (!ch[root][1])
{
int oldroot=root;root=ch[root][0];f[root]=0;clear(oldroot);return;
}
//Two Children
//找到新根,也就是x的前驱(x左子树最大的一个点),将它旋转到根。然后将原来x的右子树接到新根的右子树上
//这实际上就把x删除了,再update新根
int leftbig=pre(),oldroot=root;
splay(leftbig);//把前缀翻到根上
f[ch[oldroot][1]]=root;
ch[root][1]=ch[oldroot][1];
clear(oldroot);
update(root);
return;
}