SPLAY 未完待咕

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)

最开始树是这样的

img

我们把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){
    
    }
}
posted @ 2020-07-24 15:44  INFP  阅读(112)  评论(0编辑  收藏  举报