zoukankan      html  css  js  c++  java
  • Tyvj 1728 普通平衡树

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 13242  Solved: 5675
    [Submit][Status][Discuss]

    Description

    您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
    1. 插入x数
    2. 删除x数(若有多个相同的数,因只删除一个)
    3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
    4. 查询排名为x的数
    5. 求x的前驱(前驱定义为小于x,且最大的数)
    6. 求x的后继(后继定义为大于x,且最小的数)

    Input

    第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)

    Output

    对于操作3,4,5,6每行输出一个数,表示对应答案

    Sample Input

    10
    1 106465
    4 1
    1 317721
    1 460929
    1 644985
    1 84185
    1 89851
    6 81968
    1 492737
    5 493598

    Sample Output

    106465
    84185
    492737

    HINT

    1.n的数据范围:n<=100000

    2.每个数的数据范围:[-2e9,2e9]

    Source

    平衡树

    思路

    splay

    事实上,哨兵还是挺有用的,减轻逻辑负担;

    由于是模板题:

    t节点数值,f节点父亲编号,sz以节点为根的子树尺寸,am节点中数的个数,s节点的左右子编号;

    rot()单旋;

    splay()伸展(这里没有用双旋,因为脑模单旋和双旋操作量和结果一样,实测双旋也并不比单旋快);

    //我可能跟我师傅学了假的双旋,对于单侧链的操作和单旋一致,故而没有任何优化效果,所以和这位大佬学吧,浅谈splay的双旋

    //好吧,可能是题目,实测双旋有很强的优化效果;

    ins()添加数;

    find1()把要查找的节点旋到树根;

    find2()查找序号对应节点;

    find3()查找前驱;

    find4()查找后继;

    del()删除数;

    del():减少root节点的am值或是删除root节点;

    case1:减少root节点的sz和am值并退出;

    case2:

    将root的右子树接到root的左子树中的最右子上,同时更新从root的左子树到左子树树中最右子的路径上的节点的sz值;

    调整嫁接处的值,root改为原root的左子;

    将原root的左子树的最右子旋到根的位置;

    代码实现

     1 #include<cstdio>
     2 const int maxn=3e5;
     3 int n,ope,val;
     4 int rt,hd;
     5 int t[maxn],f[maxn],sz[maxn],am[maxn],s[maxn][2];
     6 void rot(int x){
     7     int y=f[x],z=f[y],l,r;
     8     l=s[y][0]==x?0:1,r=l^1;
     9     if(y==rt) rt=x;
    10     else{
    11         if(s[z][0]==y) s[z][0]=x;
    12         else s[z][1]=x;
    13     }
    14     f[x]=z,f[y]=x,f[s[x][r]]=y;
    15     s[y][l]=s[x][r],s[x][r]=y;
    16     sz[y]=sz[s[y][0]]+sz[s[y][1]]+am[y];
    17     sz[x]=sz[s[x][0]]+sz[s[x][1]]+am[x];
    18 }
    19 void splay(int x){while(x!=rt) rot(x);}
    20 void ins(int k,int x,int fa){
    21     if(!rt){rt=++hd,t[rt]=x,sz[rt]=1,am[rt]++;return;}
    22     while(k) fa=k,++sz[k],k=s[k][x>t[k]];
    23     k=s[fa][x>t[fa]]=++hd;
    24     t[k]=x,sz[k]=1,f[k]=fa,am[k]++;
    25     splay(k);
    26 }
    27 void find1(int k,int x){
    28     if(!k) return;
    29     while(s[k][x>t[k]]&&t[k]!=x) k=s[k][x>t[k]];
    30     splay(k);
    31 }
    32 int find2(int k,int x){
    33     if(x<=sz[s[k][0]]) return find2(s[k][0],x);
    34     if(x==sz[s[k][0]]+1) return t[k];
    35     return find2(s[k][1],x-sz[s[k][0]]-1);
    36 }
    37 int find3(int k,int x,int sum){
    38     if(!k) return sum;
    39     if(x>t[k]) return find3(s[k][1],x,t[k]);
    40     else return find3(s[k][0],x,sum);
    41 }
    42 int find4(int k,int x,int sum){
    43     if(!k) return sum;
    44     if(x<t[k]) return find4(s[k][0],x,t[k]);
    45     else return find4(s[k][1],x,sum);
    46 }
    47 void del(int k,int x){
    48     if(am[k]>1){am[k]--,sz[k]--;return;}
    49     x=s[k][1];
    50     while(s[x][0]) x=s[x][0],sz[x]+=sz[s[k][0]];
    51     f[s[k][0]]=x,s[x][0]=s[k][0],rt=s[k][1];
    52     f[rt]=0;
    53     splay(x);
    54 }
    55 int main(){
    56     freopen("phs.in","r",stdin);
    57     freopen("phs.out","w",stdout);
    58     ins(rt,-2e9-10,0),ins(rt,2e9+10,0);
    59     scanf("%d",&n);
    60     for(int i=1;i<=n;i++){
    61         scanf("%d%d",&ope,&val);
    62         if(ope==1) ins(rt,val,0);
    63         if(ope==2) find1(rt,val),del(rt,0);
    64         if(ope==3) find1(rt,val),printf("%d
    ",sz[s[rt][0]]);
    65         if(ope==4) printf("%d
    ",find2(rt,val+1));
    66         if(ope==5) printf("%d
    ",find3(rt,val,0));
    67         if(ope==6) printf("%d
    ",find4(rt,val,0));
    68     }
    69     return 0;
    70 }
    1.0

     又重新写了一遍,先手模了几棵二叉查找树,直观地认识了一下双旋对树结构的影响(对于“之”字形图,比较容易看出双旋的优越性);

    然后,优化了一下逻辑,给出了正确的双旋,使代码更加美观,跑的也稍快了。

     1 #include<cstdio>
     2 const int maxn=1e5+10;
     3 int rt,ts;
     4 int t[maxn],sz[maxn],num[maxn];
     5 int f[maxn],s[maxn][2];
     6 void rot(int x){
     7     int y=f[x],z=f[y],l,r;
     8     l=s[y][0]==x?0:1,r=l^1;
     9     if(y!=rt) s[z][s[z][1]==y]=x;
    10     f[x]=z,f[y]=x,f[s[x][r]]=s[x][r]!=0?y:0;
    11     s[y][l]=s[x][r],s[x][r]=y;
    12     sz[y]=sz[s[y][0]]+sz[s[y][1]]+num[y];
    13     sz[x]=sz[s[x][0]]+sz[s[x][1]]+num[x];
    14 }
    15 void splay(int x){
    16     int y,z;
    17     while(x!=rt){
    18         y=f[x],z=f[y];
    19         if(y==rt) rot(x),rt=x;
    20         else{
    21             rot((s[z][0]==y)==(s[y][0]==x)?y:x),rot(x);
    22             if(z==rt) rt=x;
    23         }
    24     }
    25 }
    26 void ins(int k,int x){
    27     int fa=0;
    28     while(k&&t[k]!=x) fa=k,++sz[k],k=s[k][x>t[k]];
    29     if(t[k]==x) num[k]++,sz[k]++;
    30     else{
    31         k=s[fa][x>t[fa]]=++ts;
    32         t[k]=x,sz[k]=1,f[k]=fa,num[k]=1;
    33     }
    34     splay(k);
    35 }
    36 void del(int k,int x){
    37     while(t[k]!=x)
    38     --sz[k],k=s[k][x>t[k]];
    39     num[k]--,sz[k]--;
    40     splay(k);
    41     if(!num[k]){
    42         rt=x=s[k][0];
    43         while(s[x][1]) sz[x]+=sz[s[k][1]],x=s[x][1];
    44         sz[x]+=sz[s[k][1]],s[x][1]=s[k][1],f[s[k][1]]=x;
    45     }
    46 }
    47 int query(int k,int x){
    48     while(t[k]!=x) k=s[k][x>t[k]];
    49     splay(k);
    50     return sz[s[k][0]];
    51 }
    52 int search(int k,int x){
    53     if(x<=sz[s[k][0]]) return search(s[k][0],x);
    54     if(x<=sz[s[k][0]]+num[k]) return t[k];
    55     return search(s[k][1],x-sz[s[k][0]]-num[k]);
    56 }
    57 int in_x(int k,int x,int now){
    58     if(!k) return now;
    59     if(x>t[k]){
    60         if(num[k]) return in_x(s[k][1],x,t[k]);
    61         else return in_x(s[k][1],x,now);
    62     }
    63     else return in_x(s[k][0],x,now);
    64 }
    65 int ax_x(int k,int x,int now){
    66     if(!k) return now;
    67     if(x<t[k]){
    68         if(num[k]) return ax_x(s[k][0],x,t[k]);
    69         else return ax_x(s[k][0],x,now);
    70     }
    71     else return ax_x(s[k][1],x,now);
    72 }
    73 int n,opt,x;
    74 int main(){
    75     scanf("%d",&n);
    76     rt=++ts,t[rt]=1e9,sz[rt]=1,num[rt]=1,ins(rt,-1e9);
    77     for(int i=1;i<=n;i++){
    78         scanf("%d%d",&opt,&x);
    79         if(opt==1) ins(rt,x);
    80         else if(opt==2) del(rt,x);
    81         else if(opt==3) printf("%d
    ",query(rt,x));
    82         else if(opt==4) printf("%d
    ",search(rt,x+1));
    83         else if(opt==5) printf("%d
    ",in_x(rt,x,0));
    84         else if(opt==6) printf("%d
    ",ax_x(rt,x,0));
    85     }
    86     return 0;
    87 }
  • 相关阅读:
    利用dockerfile定制镜像
    发布Docker 镜像到dockerhub
    Docker 停止容器
    133. Clone Graph
    132. Palindrome Partitioning II
    131. Palindrome Partitioning
    130. Surrounded Regions
    129. Sum Root to Leaf Numbers
    128. Longest Consecutive Sequence
    127. Word Ladder
  • 原文地址:https://www.cnblogs.com/J-william/p/6940688.html
Copyright © 2011-2022 走看看