zoukankan      html  css  js  c++  java
  • 【洛谷P3369】 (模板)普通平衡树

     https://www.luogu.org/problemnew/show/P3369

     Splay模板

      1 #include<iostream>
      2 #include<cstdio>
      3 using namespace std;
      4 #define MAXN 100010
      5 int n,sons[MAXN][2],f[MAXN],size[MAXN],cnt[MAXN],value[MAXN],root,Size;
      6 inline int read(){    //快读
      7     int x=0,ff=1; char c=getchar();
      8     while(c<'0'||c>'9') { if(c=='-') ff=-1; c=getchar(); }
      9     while('0'<=c&&c<='9') { x=(x<<3)+(x<<1)+c-'0'; c=getchar(); }
     10     return x*ff;
     11 }
     12 inline void clear(int x){  //清除节点x
     13     f[x]=sons[x][0]=sons[x][1]=size[x]=cnt[x]=value[x]=0;
     14 }
     15 inline int get_w(int p){
     16     return sons[f[p]][1]==p;
     17 }
     18 inline void update(int p){
     19     if(p){
     20         size[p]=cnt[p];
     21         if(sons[p][0]) size[p]+=size[sons[p][0]];
     22         if(sons[p][1]) size[p]+=size[sons[p][1]];
     23     }
     24 }
     25 inline void rotate(int x){  //旋转节点x
     26     int fa=f[x],gfa=f[f[x]],ws=get_w(x);
     27     sons[fa][ws]=sons[x][ws^1];  //father与son
     28     f[sons[fa][ws]]=fa;
     29     f[fa]=x;             //father与x
     30     sons[x][ws^1]=fa;
     31     f[x]=gfa;            //x与grandfather
     32     if(gfa) sons[gfa][sons[gfa][1]==fa]=x;
     33     update(x);
     34     update(fa);
     35 }
     36 inline void Splay(int x){    //将x旋到root
     37     for(int fa;fa=f[x];rotate(x))
     38      if(f[fa])
     39       rotate(get_w(x)==get_w(fa)?fa:x);  //若x,father,grandfather三个节点呈一条直线,就旋中间的节点
     40     root=x;
     41 }
     42 void insert(int x){              //插入节点
     43     if(!root){                 //如果树为空
     44         Size++;
     45         f[Size]=sons[Size][0]=sons[Size][1]=0;
     46         size[Size]=cnt[Size]=1;
     47         value[Size]=x;
     48         root=Size;
     49         return;
     50     }
     51     int now=root,fa=0;
     52     while(1){
     53         if(value[now]==x){  //如果已有的节点值=x
     54             cnt[now]++;    //该节点数量+1
     55             update(now);
     56             update(fa);
     57             Splay(now);    //旋到root,维护平衡树
     58             return;
     59         }
     60         fa=now;
     61         now=sons[now][x>value[now]];
     62         if(!now){    如果旋到叶子节点,新开一个点
     63             Size++;
     64             sons[Size][0]=sons[Size][1]=0;
     65             f[Size]=fa;
     66             size[Size]=cnt[Size]=1;
     67             value[Size]=x;
     68             sons[fa][value[fa]<x]=Size;
     69             update(fa);
     70             Splay(Size);
     71             return;
     72         }
     73     }
     74 }
     75 int find_num(int x){    //找大小顺序为x的节点的值
     76     int now=root;
     77     while(1){
     78         if(sons[now][0]&&x<=size[sons[now][0]]) now=sons[now][0];  //左子树大小>x,则向左子树查询
     79         else{
     80             int temp=(sons[now][0]?size[sons[now][0]]:0)+cnt[now];
     81             if(x<=temp) return value[now];    //x包含在cnt[now]中
     82             x-=temp;
     83             now=sons[now][1];
     84         }
     85     }
     86 }
     87 int find_rank(int x){        //查询值为x的点的大小编号
     88     int now=root,ans=0;
     89     while(1){
     90         if(x<value[now]) now=sons[now][0];
     91         else{
     92             ans+=sons[now][0]?size[sons[now][0]]:0;
     93             if(x==value[now]){
     94                 Splay(now);
     95                 return ans+1;
     96             }
     97             ans+=cnt[now];
     98             now=sons[now][1];
     99         }
    100     }
    101 }
    102 inline int find_pre(){  //root的前驱即为左子树中最靠右的点
    103     int now=sons[root][0];
    104     while(sons[now][1]) now=sons[now][1];
    105     return now;
    106 }
    107 inline int find_suf(){
    108     int now=sons[root][1];
    109     while(sons[now][0]) now=sons[now][0];
    110     return now;
    111 }
    112 void delete_node(int x){  //删除节点x
    113     find_rank(x);      //将x旋上去
    114     if(cnt[root]>1){
    115         cnt[root]--;
    116         update(root);
    117         return;
    118     }
    119     if(!sons[root][1]&&!sons[root][0]){
    120         clear(root); root=0; return;
    121     }
    122     if(!sons[root][1]){
    123         int last=root;
    124         root=sons[root][0];
    125         f[root]=0;
    126         clear(last);
    127         return;
    128     }
    129     if(!sons[root][0]){
    130         int last=root;
    131         root=sons[root][1];
    132         f[root]=0;
    133         clear(last);
    134         return;
    135     }
    136     int last=root,pre=find_pre();    //将前驱旋上去,此时x为pre的右儿子,直接删除即可(类似于链表)
    137     Splay(pre);
    138     sons[root][1]=sons[last][1];
    139     f[sons[last][1]]=root;
    140     clear(last);
    141     update(root);
    142 }
    143 int main()
    144 {
    145     n=read();
    146     int opt,x;
    147     while(n--){
    148         opt=read(); x=read();
    149         switch(opt){
    150             case 1: insert(x); break;
    151             case 2: delete_node(x); break;
    152             case 3: printf("%d
    ",find_rank(x)); break;
    153             case 4: printf("%d
    ",find_num(x)); break;
    154             case 5: insert(x);printf("%d
    ",value[find_pre()]);delete_node(x); break;
    155             case 6: insert(x);printf("%d
    ",value[find_suf()]);delete_node(x); break;
    156         }
    157     }
    158     return 0;
    159 }
  • 相关阅读:
    如何打印调试字符串?
    如何测试代码执行耗时?
    access 如何导出 cvs 文件?
    opencv如何打印长图?
    window 注册表上下文菜单如何配置?
    python 零散记录(四) 强调字典中的键值唯一性 字典的一些常用方法
    python 零散记录(三) 格式化字符串 字符串相关方法
    python 零散记录(二) 序列的相关操作 相加 相乘 改变 复制
    python 零散记录(一) input与raw_input 数学相关函数 转换字符串的方法
    devi into python 笔记(七)locals与globals 字典格式化字符串 字符集
  • 原文地址:https://www.cnblogs.com/yjkhhh/p/9206240.html
Copyright © 2011-2022 走看看