可持久化非旋Treap

版权声明:233 https://blog.csdn.net/gmh77/article/details/82755891

普通非旋Treap

这里

例题

洛谷P3835 【模板】可持久化平衡树
题目描述
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作(对于各个以往的历史版本):
插入x数
删除x数(若有多个相同的数,因只删除一个,如果没有请忽略该操作)
查询x数的排名(排名定义为比当前数小的数的个数+1。若有多个相同的数,因输出最小的排名)
查询排名为x的数
求x的前驱(前驱定义为小于x,且最大的数,如不存在输出-2147483647)
求x的后继(后继定义为大于x,且最小的数,如不存在输出2147483647)
和原本平衡树不同的一点是,每一次的任何操作都是基于某一个历史版本,同时生成一个新的版本。(操作3, 4, 5, 6即保持原版本无变化)
每个版本的编号即为操作的序号(版本0即为初始状态,空树)
输入输出格式
输入格式:

第一行包含一个正整数N,表示操作的总数。
接下来每行包含三个正整数,第 i i 行记为 v i , o p t i , x i v_i, opt_i, x_i
v i v_i 表示基于的过去版本号( 0 v i < i 0 \leq v_i < i ), o p t i opt_i 表示操作的序号( 1 o p t 6 1 \leq opt \leq 6 ), x i x_i 表示参与操作的数值

输出格式:

每行包含一个正整数,依次为各个3,4,5,6操作所对应的答案

输入输出样例
输入样例#1: 复制
10
0 1 9
1 1 3
1 1 10
2 4 2
3 3 9
3 1 2
6 4 1
6 2 9
8 6 3
4 5 8
输出样例#1: 复制
9
1
2
10
3
说明
数据范围:
对于28%的数据满足: $ 1 \leq n \leq 10 $
对于44%的数据满足: $ 1 \leq n \leq 2\cdot {10}^2 $
对于60%的数据满足: $ 1 \leq n \leq 3\cdot {10}^3 $
对于84%的数据满足: $ 1 \leq n \leq {10}^5 $
对于92%的数据满足: $ 1 \leq n \leq 2\cdot {10}^5 $
对于100%的数据满足: $ 1 \leq n \leq 5\cdot {10}^5 $ , 10 9 x i 10 9 -{10}^9 \leq x_i \leq {10}^9
经实测,正常常数的可持久化平衡树均可通过,请各位放心
样例说明:
共10次操作,11个版本,各版本的状况依次是:
[ ] []
[ 9 ] [9]
[ 3 , 9 ] [3, 9]
[ 9 , 10 ] [9, 10]
[ 3 , 9 ] [3, 9]
[ 9 , 10 ] [9, 10]
[ 2 , 9 , 10 ] [2, 9, 10]
[ 2 , 9 , 10 ] [2, 9, 10]
[ 2 , 10 ] [2, 10]
[ 2 , 10 ] [2, 10]
[ 3 , 9 ] [3, 9]

可持久化平衡树

(因为之前写的被删了所以就xjb写吧) 辣鸡csdn毁我青春
类似主席树,建N个点然后在拆分时新建点,合并时不用
(注意新建点的父亲不是原点的父亲)
证明显然。
在这里插入图片描述
拆分
在这里插入图片描述
新建点
总之由于插入的点比之前所有点的关键值都大,所以不会影响到结果(即不会产生新点)
删除就等于三次拆分

code

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define Max 20000000
#define max 2147483647
#define min -2147483647
using namespace std;

int tr[Max+1][2];
int sum[Max+1];
int fa[Max+1];
int heap[Max+1];
int num[Max+1];
int Root[Max+1];
int Now[Max+1];
int n,Q,i,j,k,l,x,y,X,Fs,Ls,I,J,type,root,Find,Find2,now,fa1,fa2;

void up(int t) {sum[t]=sum[tr[t][0]]+sum[tr[t][1]]+1;}

void New(int t,int x)
{
    n++;
    tr[n][0]=tr[tr[t][x]][0];
    tr[n][1]=tr[tr[t][x]][1];
    sum[n]=sum[tr[t][x]];
    fa[n]=t;//不是原父亲
    num[n]=num[tr[t][x]];
    heap[n]=rand()*32768+rand();
    
    tr[t][x]=n;
}

void merge(int Fa,int son,int x,int y)
{
    if (heap[x]<heap[y])
    {
        tr[Fa][son]=x;
        fa[x]=Fa;
        
        if (tr[x][1])
        merge(x,1,tr[x][1],y);
        else
        {
            sum[x]+=sum[y];
            tr[x][1]=y;
            fa[y]=x;
        }
    }
    else
    {
        tr[Fa][son]=y;
        fa[y]=Fa;
        
        if (tr[y][0])
        merge(y,0,x,tr[y][0]);
        else
        {
            sum[y]+=sum[x];
            tr[y][0]=x;
            fa[x]=y;
        }
    }
    
    if (Fa) up(Fa);
}

void split(int Fa1,int Fa2,int t,int k)
{
    if (sum[tr[t][0]]>=k)
    {
        if (!fa1) fa1=t;
        
        if (fa[t])
        {
            tr[fa[t]][tr[fa[t]][1]==t]=0;
            up(fa[t]);
        }
        
        tr[Fa1][0]=t;
        fa[t]=Fa1;
        
        if (k && tr[t][0])
        {
            New(t,0);
            split(t,Fa2,tr[t][0],k);
        }
        
        if (Fa1) up(Fa1);
    }
    else
    {
        if (!fa2) fa2=t;
        
        if (fa[t])
        {
            tr[fa[t]][tr[fa[t]][1]==t]=0;
            up(fa[t]);
        }
        
        tr[Fa2][1]=t;
        fa[t]=Fa2;
        
        if (tr[t][1])
        {
            New(t,1);
            split(Fa1,t,tr[t][1],k-sum[tr[t][0]]-1);
        }
        
        if (Fa2) up(Fa2);
    }
}

int find(int t,int k)
{
    if (sum[tr[t][0]]>=k)
    return find(tr[t][0],k);
    else
    if (sum[tr[t][0]]+1==k)
    return num[t];
    else
    return find(tr[t][1],k-sum[tr[t][0]]-1);
}

void find1(int t,int s)
{
    if (tr[t][0] && num[t]>=s)
    find1(tr[t][0],s);
    else
    if (tr[t][1] && num[t]<s)
    find1(tr[t][1],s);
    
    if (num[t]<s)
    {
        Find2+=sum[tr[t][0]]+1;
        
        if (num[t]>Find)
        Find=num[t];
    }
}

void find2(int t,int s)
{
    if (tr[t][1] && num[t]<=s)
    find2(tr[t][1],s);
    else
    if (tr[t][0] && num[t]>s)
    find2(tr[t][0],s);
    
    if (num[t]>s && num[t]<Find)
    Find=num[t];
}

int gf(int t)
{
    for (;fa[t];t=fa[t]);
    return t;
}

int main()
{
    srand(time(NULL));
    
    scanf("%d",&Q);
    
    n=0;
    now=0;
    fo(I,1,Q)
    {
        scanf("%d%d%d",&J,&type,&x);
        
        root=0;
        now=Now[J];
        if (Root[J])
        {
            n++;
            tr[n][0]=tr[Root[J]][0];
            tr[n][1]=tr[Root[J]][1];
            sum[n]=sum[Root[J]];
            num[n]=num[Root[J]];
            heap[n]=rand()*32768+rand();
            root=n;
        }
        
        switch (type)
        {
            case 1:
                {
                    n++;
                    num[n]=x;
                    sum[n]=1;
                    heap[n]=rand()*32768+rand();
                    j=n;
        			
                    if (!Root[J])
                    {
                        now++;
                        root=n;
                        break;
                    }
                    
                    Find=min;
                    Find2=0;
                    find1(root,x);
                    
                    if (!Find2)
                    merge(0,0,n,root);
                    else
                    if (Find2==now)
                    merge(0,0,root,n);
                    else
                    {
                        fa1=0,fa2=0;
                        split(0,0,root,Find2);
                        
                        merge(0,0,fa2,j);//注意这里的n会变,所以要提前记录
                        merge(0,0,gf(fa2),fa1);
                    }
                    root=gf(n);
                    
                    now++;
                    break;
                }
            case 2:
                {
                	if (!Root[J]) break;
                	
                    Find=min;
                    Find2=0;
                    find1(root,x+1);
                    
                    if (Find!=x) break;
                    
                    Find=min;
                    Find2=0;
                    find1(root,x);
                    
                    if (!Find2)
                    {
                        fa1=0,fa2=0;
                        split(0,0,root,1);
                        root=fa1;
                    }
                    else
                    if (Find2+1==now)
                    {
                        fa1=0,fa2=0;
                        split(0,0,root,now-1);
                        root=fa2;
                    }
                    else
                    {
                        fa1=0,fa2=0;
                        split(0,0,root,Find2);
                        j=fa1,k=fa2;
                        
                        fa1=0,fa2=0;
                        split(0,0,j,1);
                        
                        merge(0,0,k,fa1);
                        root=gf(k);
                    }
                    
                    now--;
                    break;
                }
            case 3:
                {
                    Find2=0;
                    find1(root,x);
                    
                    printf("%d\n",Find2+1);
                    break;
                }
            case 4:
                {
                    printf("%d\n",find(root,x));
                    break;
                }
            case 5:
                {
                    Find=min;
                    Find2=0;
                    find1(root,x);
                    
                    printf("%d\n",Find);
                    break;
                }
            case 6:
                {
                    Find=max;
                    find2(root,x);
                    
                    printf("%d\n",Find);
                    break;
                }
        }
        Root[I]=gf(root);
        Now[I]=now;
    }
}

猜你喜欢

转载自blog.csdn.net/gmh77/article/details/82755891