Stretch Tree Splay

principle

As we all know, the fhq treap code is short and powerful, but it runs slowly. The most important thing is that LCT is related to Splay. So make up for Splay. Actually, I forgot about fhq treap.

fhq treap

Single spin

Similar to fhq treap, Splay is also a binary search tree, with the nature of small left and large right. However, the core operation of fhq treap is merger and division, and the core operation of Splay is expansion.

Stretching is the tree rotation, divided into left-handed (ZAG) and right-handed (ZIG). As shown in the figure, when we perform tree rotation on the root node, we can find that left-hand and right-hand are symmetrical


Taking left-handed as a chestnut is actually making Green (right son) the father of Red (root). To satisfy the nature of AVL, Red needs to become Green's left son. Now Hong does not have a right son (the original right son, green is rotated up), and it happens that there are more left sons of green (green becomes its left son), so the left son of red, blue, is given to green as the right son. Keep the nature of AVL.

Double spin

  • Isomorphic double spin

  • Isomeric dirotation

achieve

Auxiliary operation

  • storage
struct node {
    
    
	int fa, ch[2] /*左 0 右 1*/, val, sz, cnt /*结点重复次数*/; 
}t[N];
int tot, root;
  • Query parent-child relationship
bool ident(int x, int f) {
    
    
	return t[f].ch[1] == x;
	//左 0 右 1 
}
  • Establish a father-son relationship
void connect(int x, int f, int s /*左 0 右 1*/) {
    
    
	t[f].ch[s] = x, t[x].fa = f;
} 
  • Update information
void update(int now) {
    
    
	t[now].sz = t[t[now].ls].sz + t[t[now].rs].sz + t[now].cnt;
}
  • New node
void newnode(int &now, int fa, int val) {
    
    
	now = ++tot;
	t[now].val = val, t[now].fa = fa;
	t[now].sz = t[now].cnt = 1; 
} 

stretch

  • rotate

Pass in a node xxx , to its fatherfff to rotate. The rotate operation can be seen as adjusting a point upward. Rote memorization is easy to confuse, it is recommended to push now.

void rotate(int x) {
    
    
	int f = t[x].fa, ff = t[f].fa, k = ident(x, f);
	connect(t[x].ch[k ^ 1], f, k); //挂 
	connect(x, ff, ident(f, ff)); //拎 
	connect(f, x, k ^ 1); //拎 
	update(f), update(x);
} 
  • stretch

The stretching operation relies on double rotation. After the rotate operation is implemented, the isomorphic double spin needs to rotate PP firstP , then rotateXXThe X- . And the heterogeneous double spin continuous rotateXXX twice is enough. Find a rule and find that ifident ⁡ (X, P) = ident ⁡ (P, G) \operatorname{ident}(X,P) = \operatorname{ident}(P,G)ident(X,P)=ident(P,G ) , then it is isomorphic dirotation, otherwise it is isomeric dirotation.

void splay(int x, int top) {
    
     //把 x 旋转到 top 的儿子,top 为 0 则旋转的根节点 
	if (!top) root = x;
	while (t[x].fa != top){
    
    
		int f = t[x].fa, ff = t[f].fa;
		if (ff != top) ident(x, f) ^ ident(f, ff) ? rotate(x) : rotate(f);
		rotate(x);
	}
}

Basic operation

  • Insert node

Recursive processing, after inserting the node, it needs to be extended to the root node.

void insert(int val, int &now = root, int fa = 0) {
    
    
	if (!now) newnode(now, fa, val), splay(now, 0);
	else if (val < t[now].val) insert(val, t[now].ch[0], now);
	else if (val > t[now].val) insert(val, t[now].ch[1], now);
	else t[now].cnt++, splay(now, 0);
}
  • Delete node

First recursively find the point to be deleted, and stretch it to the root node. If the number of occurrences of the root node > 1> 1>1 , then subtract1 11 is fine. Otherwise, delete the root node.

  • If the right subtree is empty, set root as the left son.
  • If the right subtree is not empty, find root's successor xxx (at the bottom left of the right subtree of root), stretch it to the right son of the root node. NowxxThe left subtree of x is empty, then putxxThe left son of x is set as the left son of root. Finally set root toxxx
void del(int val, int now = root) {
    
    
	if (val == t[now].val) {
    
    
		splay(x, 0);
		if (t[x].cnt > 1) t[x].cnt--;
		else if (t[x].ch[1]) {
    
    
			int p = t[x].ch[1];
			while (t[p].ch[0]) p = t[p].ch[0];
			splay(p, x);
			connect(t[x].ch[0], p, 0);
			root = p; update(p);
		} 
		else root = t[x].ch[0];
	} 
	else if (val < t[now].val) del(val, t[now].ch[0]);
	else del(val, t[now].ch[1]);
} 

Guess you like

Origin blog.csdn.net/qq_39984146/article/details/108119987