1. 程式人生 > >【luogu3369】【模板】普通平衡樹 [平衡樹]

【luogu3369】【模板】普通平衡樹 [平衡樹]

png 元素 技術 平衡樹 bit info space 一個 bsp

luogu3369

看的是洛谷日報上的教程 結果因為求第k大時那個判斷就出了錯導致時間超限 慘烈

技術分享圖片 技術分享圖片

技術分享圖片
  1 /*
  2 id:gww
  3 language:C--
  4    
  5 */
  6 #include<bits/stdc++.h>
  7 using namespace std;
  8 const int N=200005;
  9 int ch[N][2],val[N],cnt[N],par[N],size[N];
 10 int root,ncnt=0;
 11 //0 1代表 x的左 右兒子 val[x] x存儲的值 
 12 //cnt[x] x存儲的重復權值的個數 par[x]代表 x的父節點 
13 //size[x]代表 x子樹下的儲存的權值數(包括重復權值) 14 inline int rd() 15 { 16 int x=0,w=0;char ch=0; 17 while(!isdigit(ch)) w|=ch==-,ch=getchar(); 18 while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); 19 return w?-x:x; 20 } 21 22 void pushup(int x) {size[x]=size[ch[x][0
]]+size[ch[x][1]]+cnt[x];}//更新size數組 23 bool chk(int x) {return ch[par[x]][1]==x;}//判斷x位於它父親的方向 24 25 void rotate(int x)//旋轉 將被指定節點向上移動一級 26 { 27 int y=par[x],z=par[y],k=chk(x),w=ch[x][k^1]; 28 ch[y][k]=w;par[w]=y; 29 //父節點連向需旋轉的該子節點的方向的邊連向該子節點位於其父節點方向的反方向的節點 30 ch[z][chk(y)]=x;par[x]=z;
31 //爺爺節點連向父節點的邊連向需旋轉的該節點 32 ch[x][k^1]=y;par[y]=x; 33 //需旋轉的該節點連向該子節點位於其父節點方向的反方向的子節點的邊連向其父節點 34 pushup(y);pushup(x); 35 } 36 37 void splay(int x,int goal=0)//伸展 38 { 39 while(par[x]!=goal) 40 { 41 int y=par[x],z=par[y]; 42 if(z!=goal) 43 { 44 if(chk(x)==chk(y)) rotate(y);//三點一線 轉父親 45 else rotate(x); 46 } 47 rotate(x); 48 } 49 if(!goal) root=x; 50 } 51 52 void find(int x)//將最大的小於等於x的數所在的節點splay到根 53 { 54 // if(!root) return; 55 int cur=root; 56 while(val[cur]!=x&&ch[cur][x>val[cur]]) {cur=ch[cur][x>val[cur]];} 57 splay(cur); 58 } 59 60 void insert(int x)//插入 61 { 62 int cur=root,p=0;//從根節點開始 63 while(val[cur]!=x&&cur) {p=cur;cur=ch[cur][x>val[cur]];} //不存在 新建節點並與父節點連邊 64 if(cur) cnt[cur]++;//節點存在則直接自增cnt的值 65 else//新建節點時可能會拉出一條鏈, 66 { 67 cur=++ncnt; 68 if(p) ch[p][x>val[p]]=cur; 69 par[cur]=p;val[cur]=x; 70 ch[cur][0]=ch[cur][1]=0; 71 size[cur]=cnt[cur]=1; 72 } 73 splay(cur);//所以新建節點後需要將該節點splay到根節點 74 } 75 76 int kth(int k) 77 { 78 int cur=root; 79 while(1) 80 { 81 if (ch[cur][0] && k <= size[ch[cur][0]]) {cur = ch[cur][0];} 82 else if (k > size[ch[cur][0]] + cnt[cur]) 83 { 84 k-=size[ch[cur][0]]+cnt[cur]; 85 cur=ch[cur][1]; 86 } 87 else {return cur;} 88 } 89 } 90 91 int pre(int x)//前驅 小於這個值並且最接近這個值的元素值 92 { 93 find(x);//先初始化一個最值 94 if(val[root]<x) return root; 95 int cur=ch[root][0];//向下走 96 while(ch[cur][1]) cur=ch[cur][1]; 97 return cur; 98 } 99 int succ(int x)//後繼 大於這個值並且最接近這個值的元素值 100 { 101 find(x);//先初始化一個最值 102 if(val[root]>x) return root; 103 int cur=ch[root][1];//向下走 104 while(ch[cur][0]) cur=ch[cur][0]; 105 return cur; 106 } 107 108 void remove(int x) 109 {//把前驅splay到根,後繼splay到前驅的右兒子,那麽後繼的左兒子就是要刪除的點 110 int last=pre(x),nxt=succ(x); 111 splay(last);splay(nxt,last); 112 int del=ch[nxt][0]; 113 if(cnt[del]>1) {cnt[del]--;splay(del);} 114 else {ch[nxt][0]=0;} 115 } 116 117 int getrank(int x) 118 { 119 find(x); 120 return size[ch[root][0]]; 121 } 122 123 int main() 124 { 125 int t=rd(); 126 insert(1e9); 127 insert(-1e9); 128 while(t--) 129 { 130 int opt=rd(),x=rd(); 131 if(opt==1) insert(x); 132 if(opt==2) remove(x); 133 if(opt==3) printf("%d\n",getrank(x)); 134 if(opt==4) printf("%d\n",val[kth(x+1)]); 135 if(opt==5) printf("%d\n",val[pre(x)]); 136 if(opt==6) printf("%d\n",val[succ(x)]); 137 } 138 return 0; 139 }
100昏

【luogu3369】【模板】普通平衡樹 [平衡樹]