平衡树模板

spaly插入删除查找,前缀后缀模板

题目链接普通平衡树

​
#include<iostream>
#include<cstring>
#include<cstdio>
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 (x<key[now]) now=ch[now][0];
        else
        {
            ans+=size[ch[now][0]];
            if (x==key[now])
            {
                splay(now);
                return ans+1;
            }
            ans+=cnt[now];
            now=ch[now][1];
        }
    }
}
int findx(int x)
{
    int now=root;
    while (1)
    {
        if (x<=size[ch[now][0]]) now=ch[now][0];
        else
        {
            x-=size[ch[now][0]];
            if (x<=cnt[now])
            {
                splay(now);
                return key[now];
            }
            x-=cnt[now];
            now=ch[now][1];
        }
    }
}
int pre()
{
    int now=ch[root][0];
    while (ch[now][1]) now=ch[now][1];
    return now;
}
int nxt()
{
    int now=ch[root][1];
    while (ch[now][0]) now=ch[now][0];
    return now;
}
void del(int x)
{
    int wh=find(x);
    if (cnt[root]>1)
    {
        --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<iostream>
#include<cstring>
#include<cstdio>
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<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
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]<v];
          if (now==0)
          {
               sz++;
               ch[sz][0]=ch[sz][1]=0;key[sz]=v;size[sz]=1;
               cnt[sz]=1;f[sz]=fa;ch[fa][key[fa]<v]=sz;
               update(fa);
               splay(sz);
               break;
          }
     }
}
inline int find(int v)//查询x的排名
{
     int ans=0,now=root;
     while (1)
     {
          if (v<key[now])//v比当前结点值小,往左儿子找
               now=ch[now][0];
          else//往右找
          {
               ans+=(ch[now][0]?size[ch[now][0]]:0);//加上左子树的大小
               if (v==key[now]) {splay(now);return ans+1;}
               ans+=cnt[now];//加上权值
               now=ch[now][1];
          }
     }
}
inline int findx(int x)//查找排名为x的点
{
     int now=root;
     while (1)
     {
          if (ch[now][0]&&x<=size[ch[now][0]])//x比左子树的大小小,往左找
               now=ch[now][0];
          else
          {
               int temp=(ch[now][0]?size[ch[now][0]]:0)+cnt[now];//判断右子树的大小
               if (x<=temp)//x比右子树小直接返回
                    return key[now];
               x-=temp;now=ch[now][1];//继续往右找
          }
     }
}
//求x的前驱(后继),前驱(后继)定义为小于(大于)x,且最大(最小)的数
//这类问题可以转化为将x插入,求出树上的前驱(后继),再将x删除的问题。
inline int pre()
{
     int now=ch[root][0];
     while (ch[now][1]) now=ch[now][1];
     return now;
}
inline int next()
{
     int now=ch[root][1];
     while (ch[now][0]) now=ch[now][0];
     return now;
}
inline void del(int x)
{
     int whatever=find(x);
     if (cnt[root]>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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值