种下一棵树:有旋Treap

Posted moyiii

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了种下一棵树:有旋Treap相关的知识,希望对你有一定的参考价值。

       第一个平衡树板子,有旋Treap。用随机函数规定一个堆,维护点权的同时维护堆的性质,可以有效地避免退化成链。按我的理解,建立一棵二叉排序树,树的形态会和给出节点的顺序有关。按照出题人很机智定理,数据肯定不会太容易操作,这时候就需要我们自行调整“数据顺序”,平衡树应运而生。

       这个板子涵盖的操作有左旋、右旋(维护堆性质)、添加节点、删除节点(建树相关)、查找第x个元素、查找元素排名、查找前驱、查找后继这8种操作。改变树本身的操作都是取地址传参的,询问操作则都是简单传参。原理不是太难理解,应用则看以后刷题了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<ctime>
#include<cstdlib>
using namespace std;
const int sj=100010;
int n,opt,g,jg,cs,size;
struct tree
{
    int l,r,v,w,rnd,size;
}t[sj];
void update(int x)
{
    t[x].size=t[t[x].l].size+t[t[x].r].size+t[x].w;
}
void lturn(int &x)
{
     int tt=t[x].r;
     t[x].r=t[tt].l;
     t[tt].l=x;
     t[tt].size=t[x].size;
     update(x);
     x=tt;
}
void rturn(int &x)
{
     int tt=t[x].l;
     t[x].l=t[tt].r;
     t[tt].r=x;
     t[tt].size=t[x].size;
     update(x);
     x=tt;
}
void cr(int &x,int y)
{
     if(x==0)
     {
        size++;
        x=size;
        t[x].size=t[x].w=1;
        t[x].v=y;
        t[x].rnd=rand();
        return;
     }
     t[x].size++;
     if(t[x].v==y) t[x].w++;
     else if(y>t[x].v)
     {
         cr(t[x].r,y);
         if(t[t[x].r].rnd<t[x].rnd)  lturn(x);
     }
     else
     {
         cr(t[x].l,y);
         if(t[t[x].l].rnd<t[x].rnd)  rturn(x);
     }
}
void sc(int &k,int x)
{
     if(k==0)  return;
     if(t[k].v==x)
     {
        if(t[k].w>1)
        {
           t[k].w--;
           t[k].size--;
           return;
        }
        if(t[k].l*t[k].r==0) k=t[k].l+t[k].r;
        else if(t[t[k].l].rnd<t[t[k].r].rnd)
           rturn(k),sc(k,x);
        else
           lturn(k),sc(k,x);
     }
     else if(x>t[k].v)
          t[k].size--,sc(t[k].r,x);
     else
         t[k].size--,sc(t[k].l,x);
}
int query_rank(int k,int x)
{
    if(k==0)  return 0;
    if(t[k].v==x)  return t[t[k].l].size+1;
    else if(x>t[k].v)
      return t[t[k].l].size+t[k].w+query_rank(t[k].r,x);
    else return query_rank(t[k].l,x);
}
int query_num(int k,int x)
{
    if(k==0) return 0;
    if(x<=t[t[k].l].size)
      return query_num(t[k].l,x);
    else if(x>t[t[k].l].size+t[k].w)
      return query_num(t[k].r,x-t[t[k].l].size-t[k].w);
    else return t[k].v;
}
void query_pre(int k,int x)
{
     if(k==0) return;
     if(t[k].v<x)
        jg=k,query_pre(t[k].r,x);
     else query_pre(t[k].l,x);
}
void query_sub(int k,int x)
{
     if(k==0)  return;
     if(t[k].v>x)
        jg=k,query_sub(t[k].l,x);
     else query_sub(t[k].r,x);
}
int main()
{
    //freopen("t.txt","r",stdin);
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
       scanf("%d%d",&opt,&cs);
       if(opt==1)
         cr(g,cs);
       if(opt==2) 
         sc(g,cs);
       if(opt==3)
         printf("%d\n",query_rank(g,cs));
       if(opt==4)
         printf("%d\n",query_num(g,cs));
       if(opt==5)
       {
          jg=0;
          query_pre(g,cs);
          printf("%d\n",t[jg].v);
       }
       if(opt==6)
       {
          jg=0;
          query_sub(g,cs);
          printf("%d\n",t[jg].v);
       }
    }
    //while(1);
    return 0;
}

 

以上是关于种下一棵树:有旋Treap的主要内容,如果未能解决你的问题,请参考以下文章

模板有旋Treap

treap 学习小记

FHQ Treap

Treap模板

平衡树

Treap