题解【可持久化平衡树】

\[ Preface \]

莫得 Preface 。
\[ Description \]
【普通平衡树】的可持久化版本。
\[ Solution \]
我们知道 \(\text{fhq treap}\) 是资瓷可持久化的。

重点就在于 \(\text{fhq treap}\) 的核心操作 \(split\)\(merge\) 上,这两个操作改变了 \(\text{fhq treap}\) 的形态。

那也就是说我们在 \(split\)\(merge\) 的时候,新建立节点,将原节点的信息赋给新节点,再进行操作,使得当前版本的 \(\text{fhq treap}\) 不影响到之前版本的 \(\text{fhq treap}\) ,就达到了可持久化的目的。

split

void split_v(int p,int val,int &x,int &y)
{
    if(!p)
        x=y=0;
    else
    {
        if(t[p].val<=val)
        {
            x=++tot,t[x]=t[p];
            split_v(t[x].rc,val,t[x].rc,y),upd(x);
        }
        else
        {
            y=++tot,t[y]=t[p];
            split_v(t[y].lc,val,x,t[y].lc),upd(y);
        }
    }
}

merge

int merge(int p,int q)
{
    if(!p||!q)
        return p^q;
    else
    {
        int now=++tot;
        if(t[p].dat>t[q].dat)
            t[now]=t[p],t[now].rc=merge(t[now].rc,q);
        else
            t[now]=t[q],t[now].lc=merge(p,t[now].lc);
        upd(now);
        return now;
    }
}

但实际上 \(insert\)\(remove\) 的时候,我们在 \(split\) 的过程中已经完成了新建节点这一步,就没必要在 \(merge\) 的时候再多新建节点而保留那两棵要合并的树了。

剩下的操作只要复读复读复读就行了,或者说按有旋 \(\text{treap}\) 一样的方式做。

时空复杂度 \(Θ(n \log n)\)
\[ Code \]

#include<cstdio>
#include<cstdlib>

#define RI register int

using namespace std;

inline int read()
{
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-f;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}

const int N=500100,MLOGN=30001000;

const int INF=2147483647;

int m;

int tot,root[N];
struct treap{
    int lc,rc;
    int val,dat;
    int size;
}t[MLOGN];

int New(int val)
{
    tot++;
    t[tot].lc=t[tot].rc=0;
    t[tot].val=val,t[tot].dat=rand();
    t[tot].size=1;
    return tot; 
}

void upd(int p)
{
    t[p].size=t[t[p].lc].size+t[t[p].rc].size+1;
}

void split_v(int p,int val,int &x,int &y)
{
    if(!p)
        x=y=0;
    else
    {
        if(t[p].val<=val)
        {
            x=++tot,t[x]=t[p];
            split_v(t[x].rc,val,t[x].rc,y),upd(x);
        }
        else
        {
            y=++tot,t[y]=t[p];
            split_v(t[y].lc,val,x,t[y].lc),upd(y);
        }
    }
}

int merge(int p,int q)
{
    if(!p||!q)
        return p^q;
    if(t[p].dat>t[q].dat)
    {
        t[p].rc=merge(t[p].rc,q),upd(p);
        return p;
    }
    else
    {
        t[q].lc=merge(p,t[q].lc),upd(q);
        return q;
    }
}

int x,y,z;

void insert(int &rt,int val)
{
    split_v(rt,val-1,x,y);
    rt=New(val);
    rt=merge(x,rt);
    rt=merge(rt,y);
}

void remove(int &rt,int val)
{
    split_v(rt,val-1,x,y);
    split_v(y,val,y,z);
    y=merge(t[y].lc,t[y].rc);
    rt=merge(x,y);
    rt=merge(rt,z);
}

int GetValByRank(int p,int rank)
{
    if(!p)
        return INF;
    if(rank<=t[t[p].lc].size)
        return GetValByRank(t[p].lc,rank);
    if(rank==t[t[p].lc].size+1)
        return t[p].val;
    if(t[t[p].lc].size<rank)
        return GetValByRank(t[p].rc,rank-t[t[p].lc].size-1);
}

int GetRankByVal(int p,int val)
{
    if(!p)
        return 0;
    if(val<t[p].val)
        return GetRankByVal(t[p].lc,val);
    if(val==t[p].val)
        return t[t[p].lc].size;
    if(t[p].val<val)
        return t[t[p].lc].size+1+GetRankByVal(t[p].rc,val);
}

int GetPre(int rt,int val)
{
    int ans=-INF;
    int p=rt;
    while(p)
    {
        if(val==t[p].val)
        {
            if(t[p].lc>0)
            {
                p=t[p].lc;
                while(t[p].rc>0)p=t[p].rc;
                ans=t[p].val;
            }
            break;
        }
        if(t[p].val<val&&t[p].val>ans)ans=t[p].val;
        p=val<t[p].val?t[p].lc:t[p].rc;
    }
    return ans;
}

int GetNext(int rt,int val)
{
    int ans=INF;
    int p=rt;
    while(p)
    {
        if(val==t[p].val)
        {
            if(t[p].rc>0)
            {
                p=t[p].rc;
                while(t[p].lc>0)p=t[p].lc;
                ans=t[p].val;
            }
            break;
        }
        if(t[p].val>val&&t[p].val<ans)ans=t[p].val;
        p=val<t[p].val?t[p].lc:t[p].rc;
    }
    return ans;
}

int main()
{
    insert(root[0],-INF),insert(root[0],INF);

    m=read();

    for(RI i=1;i<=m;i++)
    {
        int ver=read(),type=read(),val=read();
        root[i]=root[ver];

        switch(type)
        {
            case 1:{
                insert(root[i],val);

                break;
            }

            case 2:{
                remove(root[i],val);

                break;
            }

            case 3:{
                printf("%d\n",GetRankByVal(root[i],val));

                break;
            }

            case 4:{
                printf("%d\n",GetValByRank(root[i],val+1));

                break;
            }

            case 5:{
                printf("%d\n",GetPre(root[i],val));

                break;
            }

            case 6:{
                printf("%d\n",GetNext(root[i],val));

                break;
            }
        }
    }

    return 0;
}

\[ Thanks \ for \ watching \]

猜你喜欢

转载自www.cnblogs.com/cjtcalc/p/12243250.html