SPLAY 未完待咕
阿新 • • 發佈:2020-07-24
Splay(還沒完先咕著)
變數定義:
\(n:節點個數~~~ch[x][2]~0代表x左兒子~1代表右兒子\)
\(val[x]x儲存的值~~cnt[x]代表x儲存的重複權個數~~fa[x]x爸爸~~siz[x]x子樹下權值數\)
操作:
chk,查詢節點父親方向
pushup,更新size陣列值
void pushup(int x){siz[x] = siz[ch[x][0]]+siz[ch[x][1]]+cnt[x]}
旋轉(rotate)
最開始樹是這樣的
我們把2號點整到4號點位置,2的下面就有子樹1,3,4,5
一種優秀做法是把4->2改成4->3,6->4改成6->2,2->3改成2->4
splay需要rotate保持平衡,核心操作,旋轉後中序遍歷和合法性保持不變
void rotate(int x){
int y = fa[x],z = fa[y],k = chk(x),w = ch[x][k^1];
ch[y][k] = w,fa[w] = y;
ch[z][chk(y)] = x;fa[x] = z;
ch[x][k^1] = y;fa[y] = x;
pushup(y);pushup(x);
}
伸展(splay)
將一個節點一路rotate到指定節點的兒子。如果該點,fa,grandfa節點三點一線,應該先轉fa
void splay(int x,int goal = 0){ while(fa[x] != goal){ int y =fa[x],z = fa[y]; if(z != goal){ if(chk(x) == chk(y)) rotate(y); else rotate(x); } rotate(x); } if(!goal) root = x; }
find操作
void find(int x){
if(!root) return;
int cur = root;
while(ch[cur][x > val[cur]] && x != val[cur]){
cur = ch[cur][x > val[cur]];
}
splay(cur);
}
insert插入
從根節點開始,一路搜尋下去。如果節點存在則直接自增cnt的值。否則新建節點並與父節點連邊。因為新建節點時可能會拉出一條鏈,所以新建節點後需要將該節點splay到根節點。沿途的rotate操作可以使平衡樹恢復平衡。
void insert(int x){ int cur = root,p = 0; while(cur && val[vur] != x){ } }