平衡树点分裂

关于\(\tt{FHQ}\)平衡树点分裂的写法

前言:最近感觉不怎么想写平衡树了,然后今天发现仅有的会写的三种平衡树(\(FHQtreap,splay,Scapegoat \ Tree\)),基本上只会打\(FHQ\)了(这个东西真的太好打了

不过\(\tt{NOIp}\)还是复习一下,虽然常数比较大所以我一定会优先考虑线段树的

今天回去打了一下列队,决定统一一下自己点分裂的写法

一般来说,点分裂时,平衡树每个点都代表一段区间\([l,r]\)

当需要区间分裂的时候,我们不妨就在\(\tt{split}\)的里面进行分裂

#define siznow (segr[now]+1-segl[now])
void split(int now,int k,int &x,int &y)
{
    if(!now) {x=y=0;return;}
    if(siz[ls]>=k)
        y=now,split(ls,k,x,ls),updata(y);
    else if(k>=siznow+siz[ls])
        x=now,split(rs,k-siznow-siz[ls],rs,y),updata(x);
    else
    {
        ll p=k-siz[ls]+segl[now]-1;
        x=Merge(ch[now][0],New(segl[now],p));
        y=Merge(New(p+1,segr[now]),ch[now][1]);
    }
}

恩,感觉还是蛮方便的,以后就这么写了

列队的完整代码

#include <cstdio>
#include <cstdlib>
#define ls ch[now][0]
#define rs ch[now][1]
#define ll long long
const int N=2400000;
int ch[N][2],val[N],root[N],tot,q;
ll segl[N],segr[N],siz[N],n,m;
#define siznow (segr[now]-segl[now]+1)
void updata(int now){siz[now]=siz[ls]+siz[rs]+siznow;}
int Merge(int x,int y)
{
    if(!x||!y) return x+y;
    if(val[x]<val[y])
    {
        ch[x][1]=Merge(ch[x][1],y);
        updata(x);
        return x;
    }
    else
    {
        ch[y][0]=Merge(x,ch[y][0]);
        updata(y);
        return y;
    }
}
int New(ll l,ll r)
{
    if(l>r) return 0;
    siz[++tot]=r+1-l,val[tot]=rand(),segl[tot]=l,segr[tot]=r;
    return tot;
}
void split(int now,int k,int &x,int &y)
{
    if(!now) {x=y=0;return;}
    if(siz[ls]>=k)
        y=now,split(ls,k,x,ls),updata(y);
    else if(k>=siznow+siz[ls])
        x=now,split(rs,k-siznow-siz[ls],rs,y),updata(x);
    else
    {
        ll p=k-siz[ls]+segl[now]-1;
        x=Merge(ch[now][0],New(segl[now],p));
        y=Merge(New(p+1,segr[now]),ch[now][1]);
    }
}
void Insert(int id,ll p,ll d)
{
    int x,y;
    split(root[id],p,x,y);
    root[id]=Merge(x,Merge(New(d,d),y));
}
ll query(int id,ll p)
{
    int x,y,z;
    split(root[id],p,x,y);
    split(x,p-1,x,z);
    ll ret=segl[z];
    root[id]=Merge(x,y);
    return ret;
}
int main()
{
    scanf("%lld%lld%d",&n,&m,&q);
    for(ll i=1;i<=n;i++)
    {
        Insert(n+1,i,i*m);
        root[i]=New(1+(i-1)*m,i*m-1);
    }
    ll ans,rig;
    for(int x,y,i=1;i<=q;i++)
    {
        scanf("%d%d",&x,&y);
        if(y==m)
        {
            ans=query(n+1,x);
            Insert(n+1,n,ans);
        }
        else
        {
            ans=query(x,y);
            rig=query(n+1,x);
            Insert(n+1,n,ans);
            Insert(x,m-1,rig);
        }
        printf("%lld\n",ans);
    }
    return 0;
}

2018.11.6

posted @ 2018-11-06 19:40  露迭月  阅读(235)  评论(0编辑  收藏  举报