Treap-普通平衡树

来源:互联网 发布:2017吉大网络教育收费 编辑:程序博客网 时间:2024/04/27 20:34

https://www.luogu.org/problem/show?pid=3369
最近学习了treap,找了道题目做做 全抄hz...
因为普通的二叉树,会退化成链;
所以你把读入打乱顺序再构造二叉树,就明显卡不掉;
平平均深度logn;
treap就是这样的;
在插入一个数时,我们搞一个rnd,赋值随机;
然后如果当前的这个节点rnd小于其父节点,那么就把他转到父节点的位置;
这样好比是给这个节点一个随机的顺序;
那么即使毒瘤出题人把一开始数据的顺序搞特殊,故意要卡你,因为每个数据有了这么一个随机位置,相当于把读入打乱啦,所以卡不掉;
要是被卡了是RP问题;
http://baike.baidu.com/link?url=VNd3Gm-SrYJpjVllSPRvnjBV5MwdxH8wnwUY5HNp3agTInLjpte8a0a_pGerSz3u2yysC76xy9zzntbYX1GfMq
百度百科;
我们浅谈关于转;

这里写图片描述
这里我们要把3节点转到上面来;
我们发现转好之后几个数字的再二叉树里的大小关习是不变的;
这就是我们转的原理;
可以看出2-1|||||||||3-5这两条边是不变的;
自己感受感受;
其实转就是怎么个过程,换了种方式存储信息;
但转就把3节点向上移动了;


代码

#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>using namespace std;struct treap{    int l,r,v,size,w,rnd;//size是包括根节点,这个子树的节点总数,w是这个v值出现了几次,所以treap里面每个值只有一个; }tr[100005];int m,x,y,z,root,size;//root是根节点,根节点不一定是1,因为会转掉的;size就个计数 void now(int k){tr[k].size=tr[tr[k].l].size+tr[tr[k].r].size+tr[k].w;}//更新size void lturn(int &k){//这个过程建议大家直接好好模拟,思考;     int t=tr[k].r;    tr[k].r=tr[t].l;    tr[t].l=k;    tr[t].size=tr[k].size;    now(k);    k=t;}void rturn(int &k){    int t=tr[k].l;    tr[k].l=tr[t].r;    tr[t].r=k;    tr[t].size=tr[k].size;    now(k);    k=t;}void insert(int &k,int x){    if(!k){        k=++size;        tr[k].size=tr[k].w=1;        tr[k].v=x;        tr[k].rnd=rand();//我们只需要一组随机数,所以不用种子;         return;    }    tr[k].size++;    if(tr[k].v==x){tr[k].w++;return;}//如果已经出现过直接加再w上     if(tr[k].v<x){        insert(tr[k].r,x);//先找到叶节点的位置,再不断旋转上升;         if(tr[tr[k].r].rnd<tr[k].rnd)lturn(k);//左节点右旋;     }else{        insert(tr[k].l,x);        if(tr[tr[k].l].rnd<tr[k].rnd)rturn(k);    }   }void del(int &k,int x){    if(!k)return;    if(tr[k].v==x){        if(tr[k].w>1){tr[k].size--;tr[k].w--;return;}//如果有多个那删一个         if(tr[k].l*tr[k].r==0){k=tr[k].l+tr[k].r;return;}//这个是有一个节点和无节点的情况         int l=tr[k].l,r=tr[k].r;        if(tr[l].rnd<tr[r].rnd)rturn(k);else lturn(k);//x转到下一层,直到转到叶子节点         del(k,x);        return;    }    tr[k].size--;    if(tr[k].v<x)del(tr[k].r,x);else del(tr[k].l,x);//先找到位置 }int Rank(int k,int x){    if(!k)return 0;    if(tr[k].v==x)return     tr[tr[k].l].size+1;    if(tr[k].v>x)return Rank(tr[k].l,x);    return tr[tr[k].l].size+tr[k].w+Rank(tr[k].r,x);}int num(int k,int x){    if(!k)return 0;    if(x<=tr[tr[k].l].size)return num(tr[k].l,x);    if(x>tr[tr[k].l].size+tr[k].w)return num(tr[k].r,x-tr[tr[k].l].size-tr[k].w);    return tr[k].v;}int pro(int k,int x){//推荐大家用hzwer的写法,这个写法比较乱     if(!k)return 0;    if(tr[k].v>=x)return pro(tr[k].l,x);    int ans=pro(tr[k].r,x);    if(ans)return ans;else return tr[k].v;}int sub(int k,int x){    if(!k)return 0;    if(tr[k].v<=x)return sub(tr[k].r,x);    int ans=sub(tr[k].l,x);    if(ans)return ans;else return tr[k].v;}int main(){    scanf("%d",&m);    while(m--){        scanf("%d%d",&y,&x);        if(y==1)insert(root,x);else        if(y==2)del(root,x);else        if(y==3)printf("%d\n",Rank(root,x));else        if(y==4)printf("%d\n",num(root,x));else        if(y==5)printf("%d\n",pro(root,x));else        if(y==6)printf("%d\n",sub(root,x));    }}
1 2
原创粉丝点击