码迷,mamicode.com
首页 > 其他好文 > 详细

平衡树模板

时间:2018-06-20 22:32:54      阅读:225      评论:0      收藏:0      [点我收藏+]

标签:problem   维护   switch   style   The   define   div   play   rand   

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

 

 

  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\n",find_rank(x)); break;
153             case 4: printf("%d\n",find_num(x)); break;
154             case 5: insert(x);printf("%d\n",value[find_pre()]);delete_node(x); break;
155             case 6: insert(x);printf("%d\n",value[find_suf()]);delete_node(x); break;
156         }
157     }
158     return 0;
159 }

 

平衡树模板

标签:problem   维护   switch   style   The   define   div   play   rand   

原文地址:https://www.cnblogs.com/yjkhhh/p/9206240.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!