1. 程式人生 > >平衡樹模板

平衡樹模板

ase 清除 else nbsp ++ HA 一個 bre nod

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 }

平衡樹模板