Treap

· · 个人记录

Treap

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
#define maxn 1000050
using namespace std;
int n;
struct Treap{//Treap:BST+小根堆(随机权值保证BST不是一条链继而保证复杂度) 
    //0:left;1:right
    int root,tot,siz[maxn],w[maxn],pos[maxn];
    int s[maxn][2];
    void push_up(int i){siz[i]=siz[s[i][0]]+siz[s[i][1]]+1;}
    void rotate(int &i,int p)
    {
        int t=s[i][p];
        s[i][p]=s[t][!p];
        s[t][!p]=i;
        push_up(i); push_up(t);
        i=t;
    }
    void ins(int x,int &i)
    {
        if(!i){i=++tot;siz[i]=1;w[i]=x;pos[i]=rand();return;}
        siz[i]++;
        int p=(x>w[i]?1:0);
        ins(x,s[i][p]);
        if(pos[s[i][p]]<pos[i]) rotate(i,p);//将i和儿子p交换 
    }    
    void del(int x,int &i)
    {
        if(w[i]==x)
        {
            if(!s[i][0]||!s[i][1]){i=s[i][0]+s[i][1];return;}
            int p=pos[s[i][0]]>pos[s[i][1]]?1:0;
            rotate(i,p); del(x,s[i][p^1]);
        }
        else if(w[i]>x)del(x,s[i][0]);
        else del(x,s[i][1]);
        push_up(i);
    }
    int queryrank(int x,int i)//寻找x的排名
    {
        if(!i)return 1;
        if(w[i]>=x)return queryrank(x,s[i][0]);
        else return queryrank(x,s[i][1])+siz[s[i][0]]+1;
    }
    int queryk(int x,int i)//寻找第x大 
    {
        if(siz[s[i][0]]==x-1)return w[i];
        if(siz[s[i][0]]>=x)return queryk(x,s[i][0]);
        else return queryk(x-siz[s[i][0]]-1,s[i][1]);
    }
    int querypre(int x,int i)//找前驱
    {
        if(!i)return -inf;
        if(w[i]<x)return max(w[i],querypre(x,s[i][1]));
        else return querypre(x,s[i][0]);
    }
    int querynxt(int x,int i)
    {
        if(!i)return inf;
        if(w[i]>x)return min(w[i],querynxt(x,s[i][0]));
        else return querynxt(x,s[i][1]);
    }
}tr;

int main()
{
    //srand(time(0));
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int opt,x; scanf("%d%d",&opt,&x);
        if(opt==1)tr.ins(x,tr.root);
        if(opt==2)tr.del(x,tr.root);
        if(opt==3)cout<<tr.queryrank(x,tr.root)<<endl;
        if(opt==4)cout<<tr.queryk(x,tr.root)<<endl;
        if(opt==5)cout<<tr.querypre(x,tr.root)<<endl;
        if(opt==6)cout<<tr.querynxt(x,tr.root)<<endl;
    }
}

无旋Treap

#include<bits/stdc++.h>
#define maxn 100005
using namespace std;
int n,m,rt;
struct fhqTreap{//将Treap的主属性从BST转为小根堆, pos[]:按小根堆排列; w[]:按BST排列
    int w[maxn],siz[maxn],pos[maxn],tot;
    int s[maxn][2];
    int lazy[maxn];//lazy标记:区间是否翻转 
    void push_up(int i){siz[i]=siz[s[i][0]]+siz[s[i][1]]+1;}
    void push_down(int i)//区间翻转下传标记 
    {
        swap(s[i][0],s[i][1]);
        if(s[i][0])lazy[s[i][0]]^=1;
        if(s[i][1])lazy[s[i][1]]^=1;
        lazy[i]=0;
    }
    int newcode(int x)
    {
        w[++tot]=x;siz[tot]=1;pos[tot]=rand();
        return tot;
    }
    int merge(int x,int y)
    {
        if(!x||!y)return x+y;
        if(pos[x]<pos[y])//以x为根
        {
            if(lazy[x]) push_down(x);
            s[x][1]=merge(s[x][1],y); push_up(x);
            return x;
        }
        else
        {
            if(lazy[y]) push_down(y);
            s[y][0]=merge(x,s[y][0]); push_up(y);
            return y;
        }
    }
    void split(int i,int k,int &x,int &y)
    {
        if(!i){ x=y=0; return; }
        if(lazy[i])push_down(i);
        if(k<=siz[s[i][0]])
            y=i,split(s[i][0],k,x,s[i][0]);
        else 
            x=i,split(s[i][1],k-siz[s[i][0]]-1,s[i][1],y);
        push_up(i);
    }
    void print(int i)
    {
        if(!i)return;
        if(lazy[i])push_down(i);
        print(s[i][0]);
        printf("%d ",w[i]);
        print(s[i][1]);
    }
    int query(int now,int k)//查询排名为k的数
    {
        if(k==siz[s[now][0]]+1)return w[now];
        if(lazy[now])push_down(now);
        if(k<=siz[s[now][0]])
            return query(s[now][0],k);
        else return query(s[now][1],k-siz[s[now][0]]-1);
    }
}tr;

void ins(int a)//插入一个元素
{
    int x,y;
    tr.split(rt,a,x,y);
    rt=tr.merge(tr.merge(x,tr.newcode(a)),y);
}
void del(int x)//删除一个元素
{
    int a,b,c;
    tr.split(rt,x,b,c);
    tr.split(b,x-1,a,b);
    b=tr.merge(tr.s[b][0],tr.s[b][1]);
    rt=tr.merge(tr.merge(a,b),c);

}
int queryrank(int k)//查询数k的排名
{
    int x,y,z,ret;
    tr.split(rt,k-1,x,y);
    ret=tr.siz[x]+1;
    rt=tr.merge(x,y);
    return ret;
}
int querypre(int k)//查询数k的前驱
{
    int x,y,ret;
    tr.split(rt,k-1,x,y);
    ret=tr.query(x,tr.siz[x]);
    rt=tr.merge(x,y);
    return ret;
}
int querynxt(int k)//查询数k的后继
{
    int x,y,ret;
    tr.split(rt,k,x,y);
    ret=tr.query(y,1);//查询y中第一个数
    rt=tr.merge(x,y);
    return ret;
}
void turn(int l,int r)//翻转区间[l,r]
{
    int a,b,c;
    tr.split(rt,r,b,c);
    tr.split(b,l-1,a,b);
    tr.lazy[b]^=1;
    rt=tr.merge(a,tr.merge(b,c));
}
int main()
{
    n=read(); 
    for(int i=1;i<=n;i++) 
    {
        int opt=read(); int x=read();
        if(opt==1)ins(x);
        if(opt==2)del(x);
        if(opt==3)printf("%lld\n",queryrank(x));
        if(opt==4)printf("%lld\n",tr.query(rt,x));
        if(opt==5)printf("%lld\n",querypre(x));
        if(opt==6)printf("%lld\n",querynxt(x));
        if(opt==7){ int l=x,r=read();turn(l,r);}
        if(opt==8){tr.print(rt);cout<<endl;}
    }
}

Treap和笛卡尔树

例题:文本编辑器

利用笛卡尔树建树,O(n)建树减少复杂度。

 int build(int *a,int k)
    {
        int top=0;
        for(int i=1;i<=k;i++)
        {
            newcode(a[i]);int l=0;
            while(top&&pos[st[top]]>pos[tot])push_up(st[top]),l=st[top--];
            if(top)s[st[top]][1]=tot;
            s[tot][0]=l;
            st[++top]=tot;
        }
        while(top)
        {
            push_up(st[top--]);
        }
        return st[1];
    }

按排名split与按权值split

排名:

    void split(int i,int k,int &x,int &y)
    {
        if(!i){ x=y=0; return; }
        if(lazy[i])push_down(i);
        if(k<=siz[s[i][0]])//第i个节点在y中
            y=i,split(s[i][0],k,x,s[i][0]);
        else 
            x=i,split(s[i][1],k-siz[s[i][0]]-1,s[i][1],y);
        push_up(i);
    }

权值:

    void split(int i,nod k,int &x,int &y)
    {
        if(!i){x=y=0;return;}
        if(w[i]>k)//第i个节点在y中
            y=i,split(s[i][0],k,x,s[i][0]);
        else 
            x=i,split(s[i][1],k,s[i][1],y);
        push_up(i);
    }

无旋Treap删除一个元素

    int x,y,z; 
    tr.split(rt,a,x,y);
    tr.split(x,a-1,x,z);
    z=tr.merge(tr.s[z][0],tr.s[z][1]);
    rt=tr.merge(tr.merge(x,z),y);