splay

前置

竞赛中比较常用。

闲扯:一般没有人会在考场上面写红黑树。

splay可以处理很多和线段树有关的问题,但是更加灵活。

splay是一棵比较平衡的二叉树,维护的是中序遍历的有序序列。

左旋和右旋保证树的高度是logn的,但是不改变树的中序遍历。

核心:每次操作一个节点,均将该节点旋转到树根。(证明过于复杂,我直接忽略),保证旋转的时间复杂度平均是logn的。

操作

1.splay(x, k)将点x旋转到k的下面。如果k是0,代表将x旋转到根。z -> y -> x,一条链,先转y再转x。有曲折的,先转x再转x

2.将一个序列插入到y的后面:首先找打y的后继z,首先将y转到跟,然后将z转到y的下面。因为z是y的后继,所以z在y的右子树上面,而且z的左子树为空,那么可以直接将序列插入到z的左子树上面去。

3.删除一段(l, r)转一下,然后删除r后继的左子树。

splay如何维护信息
1.每一个子树的节点个数。

2.flag懒标记,这个区间需不需要翻转。

3.push_up维护根节点的信息,push_down用来下传懒标记。

Splay

#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, m, rt = 0, cnt = 0;
struct tree
{
	int siz, f, v, lz, son[2];
	void init(int _v, int _p) {siz = 1, v = _v, f = _p; }
	
}t[N];
void push_down(int x)
{
	if(t[x].lz)
	{
		t[t[x].son[0]].lz ^= 1, t[t[x].son[1]].lz ^= 1;
		swap(t[x].son[0], t[x].son[1]);
		t[x].lz = 0;
	}
	return ;
}
void push_up(int p)
{
	t[p].siz = t[t[p].son[1]].siz + t[t[p].son[0]].siz + 1;
	return ;
}
void rotate(int x)
{
	int y = t[x].f, z = t[y].f;
	t[x].f = z, t[z].son[y == t[z].son[1]] = x;
	
	int ch = (x == t[y].son[1]);
	t[y].son[ch] = t[x].son[ch ^ 1], t[t[x].son[ch ^ 1]].f = y;
	
	t[y].f = x, t[x].son[ch ^ 1] = y;
	push_up(y), push_up(x);
}
void splay(int x, int k)
{
	while(t[x].f != k)
	{
		int y = t[x].f, z = t[y].f;
		if(z != k) 
		{
			if((t[y].son[1] == x) ^ (t[z].son[1] == y)) rotate(x);
			else rotate(y); 
		}
		rotate(x);
	}
	if(k == 0) rt = x;
	return ;
}
int find_rank(int k)
{
	int u = rt;
	while(u)
	{
		push_down(u);
		if(k <= t[t[u].son[0]].siz) u = t[u].son[0];
		else if(k == t[t[u].son[0]].siz + 1) return u;
		else k = k - t[t[u].son[0]].siz - 1, u = t[u].son[1];
	}
	return - 1;
}
void insert(int v)
{
	int u = rt, p = 0;
	while(u) p = u, u = t[u].son[v > t[u].v];
	u = ++ cnt;
	if(p != 0) t[p].son[v > t[p].v] = u;
	t[u].init(v, p);
	splay(u, 0);
}
void write(int x)
{
	if(x == 0) return ;
	push_down(x);
	write(t[x].son[0]);
	if(1 <= t[x].v && t[x].v <= n)printf("%d ", t[x].v);
	write(t[x].son[1]);
	return ;
}
int main()
{
	scanf("%d %d", &n, &m);	
	for (int i = 0; i <= n + 1; ++ i) insert(i);
	while(m --)
	{
		int l, r;
		scanf("%d %d", &l, &r);
		l = find_rank(l), r = find_rank(r + 2);
		splay(l, 0), splay(r, l);
		t[t[r].son[0]].lz ^= 1;
	}
	write(rt);
}

郁闷的出纳员

#include <bits/stdc++.h>
using namespace std;
const int N = 100005, inf = 0x3f3f3f3f;
int n, delta = 0, mn, tot = 0, rt = 0;
struct tree
{
	int siz, par, son[2], val;
	void init(int _val, int _par) {siz = 1, par = _par, val = _val; return; }
	
}t[N];
void push_up(int p) {t[p].siz = t[t[p].son[0]].siz + t[t[p].son[1]].siz + 1; }
void rotate(int x)
{
	int y = t[x].par, z = t[y].par, k = (x == t[y].son[1]);
	t[z].son[y == t[z].son[1]] = x, t[x].par = z;
	
	t[y].son[k] = t[x].son[k ^ 1], t[t[x].son[k ^ 1]].par = y;
	
	t[x].son[k ^ 1] = y, t[y].par = x;
	
	push_up(y), push_up(x);
	return ;
}
void splay(int x, int k)
{
	while(t[x].par != k)
	{
		int y = t[x].par, z = t[y].par;
		if(z != k)
		{
			if((y == t[z].son[1]) ^ (x == t[y].son[1])) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
	if(!k) rt = x;
	return ;
}
void insert(int v)
{
	int u = rt, p = 0;
	while(u) p = u, u = t[u].son[v > t[u].val];
	u = ++ tot; t[u].init(v, p);
	if(p) t[p].son[v > t[p].val] = u;
	splay(u, 0);
	return ;
}
int get(int x)
{
	int u = rt, ans = 0;
	while(u)
	{
		if(t[u].val >= x) ans = u, u = t[u].son[0];
		else u = t[u].son[1]; 
	}
	return ans;
}
int get_k(int k)
{
	int u = rt;
//	printf("%d!\n", u);
	while(u)
	{
		if(t[t[u].son[0]].siz >= k) u = t[u].son[0];
		else if(t[t[u].son[0]].siz + 1 == k) return t[u].val;
		else k = k - t[t[u].son[0]].siz - 1, u = t[u].son[1];
	}
	return -1; 
}
int main()
{
	scanf("%d %d", &n, &mn);
	insert(-inf), insert(inf);
	for (int i = 1; i <= n; ++ i)
	{
		char opt[3];
		int x;
		scanf("%s %d", opt, &x);
		if(opt[0] == 'I')
		{
			if(x >= mn) insert(x - delta);
		}
		else if(opt[0] == 'A') delta += x;
		else if(opt[0] == 'S')
		{
			delta -= x;
			int L = get(-inf), R = get(mn - delta);
			splay(L, 0), splay(R, L), t[R].son[0] = 0;
			push_up(R), push_up(L);
//			splay(R, 0), splay(L, R); t[L].son[1] = 0;
//			push_up(L), push_up(R);
		}
		else if(opt[0] == 'F')
		{
			if(x > t[rt].siz - 2) 
			{
				printf("-1\n");
				continue;
			}
			printf("%d\n", get_k(t[rt].siz - x) + delta);
		}
	}
	printf("%d", tot - t[rt].siz);
	return 0;
}

永无乡

#include <bits/stdc++.h>
using namespace std;
const int N = 400005;
struct tree
{
	int siz, val, par, son[2], idx;
	void init (int _val, int _par, int _idx)
	{
		siz = 1, val = _val, par = _par, idx = _idx, son[0] = son[1] = 0; return ;
	}
	
}t[N];
int fa[N], n, m, q, tot = 0, rt[N];
int findset(int x)
{
	if(fa[x] == x) return x;
	else return fa[x] = findset(fa[x]);
}
void push_up(int p) {t[p].siz = t[t[p].son[0]].siz + t[t[p].son[1]].siz + 1; }
void rotate(int x)
{
	int y = t[x].par, z = t[y].par, k = x == t[y].son[1];
	t[z].son[y == t[z].son[1]] = x, t[x].par = z;
	
	t[y].son[k] = t[x].son[k ^ 1], t[t[x].son[k ^ 1]].par = y;
	
	t[x].son[k ^ 1] = y, t[y].par = x;
	push_up(y), push_up(x);
	return ;
}

void splay(int x, int k, int b)
{
	while(t[x].par != k)
	{
		int y = t[x].par, z = t[y].par;
		if(z != k)
		{
			if((t[y].son[1] == x) ^ (t[z].son[1] == y)) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
	if(!k) rt[b] = x;
	
	return ;
}
void insert(int v, int b, int idx)
{
	int u = rt[b], p = 0;
	while(u) p = u, u = t[u].son[v > t[u].val];
	u = ++ tot;
	t[u].init(v, p, idx);
	if(p) t[p].son[v > t[p].val] = u;
	splay(u, 0, b);
	return ;
}
void dfs(int x, int b)
{
	if(t[x].son[1]) dfs(t[x].son[1], b);
	if(t[x].son[0]) dfs(t[x].son[0], b);
	insert(t[x].val, b, t[x].idx);
	return ;
}
int get(int b, int k)
{
	int u = rt[b];
	while(u)
	{
		if(t[t[u].son[0]].siz >= k) u = t[u].son[0];
		else if(k == t[t[u].son[0]].siz + 1) return t[u].idx;
		else k = k - t[t[u].son[0]].siz - 1, u = t[u].son[1];
	}
	return - 1;
}
int main()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++ i) 
	{
		rt[i] = 0, fa[i] = i;
		int v; scanf("%d", &v);
		insert(v, i, i);
	}
	while(m --)
	{
		int u, v;
		scanf("%d %d", &u, &v);
		u = findset(u), v = findset(v);
		if(u == v) continue;
		if(t[rt[u]].siz > t[rt[v]].siz) dfs(v, u), fa[v] = u;
		else dfs(u, v), fa[u] = v;
 	}
//	for (int i = 1; i <= n; ++ i) printf("%d ", rt[findset(i)]);
//	printf("\n");
 	scanf("%d", &q);
 	while(q --)
 	{
 		char opt[2]; int u, v; scanf("%s %d %d", opt, &u, &v);
 		if(opt[0] == 'B')
 		{
			u = findset(u), v = findset(v);
			if(u == v) continue;
			if(t[rt[u]].siz > t[rt[v]].siz) dfs(v, u), fa[v] = u;
			else dfs(u, v), fa[u] = v;
		}
		else
		{
			u = findset(u);
			if(t[rt[u]].siz < v) printf("-1\n");
			else printf("%d\n", get(u, v));
		}
	}
}

维护数列

#include <bits/stdc++.h>
using namespace std;
const int N = 1000010;
const int inf = 0x3f3f3f3f;
int n, m, tot = 0, nodes[N], w[N], rt = 0;
struct tree
{
	int val, par, son[2], siz;
	int rev, al;
	int sum, ms, ls, rs;
	void init(int _val, int _par)
	{
		val = _val, par = _par, siz = 1, son[0] = son[1] = 0;
		rev = al = 0;
		sum = _val, ms = _val, ls = max(_val, 0), rs = max(_val, 0);
		return ;	
	}
} t[N];
void push_up(int p)
{
	tree &u = t[p], &l = t[t[p].son[0]], &r = t[t[p].son[1]];
	u.siz = l.siz + r.siz + 1, u.sum = l.sum + r.sum + u.val;
	u.ls = max(l.ls, l.sum + u.val + r.ls), u.rs = max(r.rs, r.sum + u.val + l.rs);
	u.ms = max(r.ms, max(l.ms, l.rs + u.val + r.ls));//这里是两个端点的ms! 
	return ;
}
void rotate(int x)
{
	int y = t[x].par, z = t[y].par;
	int k = (x == t[y].son[1]);
	t[x].par = z, t[z].son[t[z].son[1] == y] = x;
	t[y].son[k] = t[x].son[k ^ 1], t[t[x].son[k ^ 1]].par = y;
	t[x].son[k ^ 1] = y, t[y].par = x;
	push_up(y), push_up(x);
	return ;
}
void splay(int x, int k)
{
	while(t[x].par != k)
	{
		int y = t[x].par, z = t[y].par;
		if(z != k)
		{
			if((t[z].son[1] == y) ^ (t[y].son[1] == x)) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
	if(!k) rt = x;
	return ;
}
void push_down(int p)
{
	tree &u = t[p], &l = t[t[p].son[0]], &r = t[t[p].son[1]];
	if(u.al)
	{
		u.al = u.rev = 0;
		if(u.son[0]) l.val = u.val, l.sum = l.val * l.siz, l.ls = max(0, l.sum), l.rs = max(0, l.sum), l.ms = max(l.val, l.sum), l.al = 1;
		if(u.son[1]) r.val = u.val, r.sum = r.val * r.siz, r.ls = max(0, r.sum), r.rs = max(0, r.sum), r.ms = max(r.val, r.sum), r.al = 1; 
	}
	else if(u.rev)
	{
		u.rev = 0;
		l.rev ^= 1, swap(l.son[0], l.son[1]), swap(l.ls, l.rs);
		r.rev ^= 1, swap(r.son[0], r.son[1]), swap(r.ls, r.rs);
	} 
	return ;
} 
int get_k(int k)
{
	int u = rt;
	while(u)
	{
		push_down(u);
		if(t[t[u].son[0]].siz >= k) u = t[u].son[0];
		else if(t[t[u].son[0]].siz + 1 == k) return u;
		else k = k - t[t[u].son[0]].siz - 1, u = t[u].son[1];
	}
	return - 1;
}
int build(int l, int r, int b)
{
	int mid = (l + r) >> 1, u = nodes[tot --];
	t[u].init(w[mid], b);
	if(l < mid) t[u].son[0] = build(l, mid - 1, u);
	if(mid < r) t[u].son[1] = build(mid + 1, r, u);
	push_up(u);
	return u;
}
void dfs(int u)
{
	if(t[u].son[0]) dfs(t[u].son[0]);
	if(t[u].son[1]) dfs(t[u].son[1]);
	nodes[++ tot] = u;
	return ;
}
int main()
{
	for (int i = 500000; i >= 1; -- i) nodes[++ tot] = i;
	scanf("%d %d", &n, &m);
	t[0].ms = w[0] = w[n + 1] = -inf;
	for (int i = 1; i <= n; ++ i) scanf("%d", &w[i]);	
	rt = build(0, n + 1, 0);
	while(m --)
	{
		char opt[20];
		scanf("%s", opt);
		if(!strcmp(opt, "INSERT"))
		{
			int pos, x; 
			scanf("%d %d", &pos, &x);
			for (int i = 1; i <= x; ++ i) scanf("%d", &w[i]);
			int l = get_k(pos + 1), r = get_k(pos + 2);
			splay(l, 0), splay(r, l);
			t[r].son[0] = build(1, x, r); 
			push_up(r), push_up(l);
		}
		else if(!strcmp(opt, "DELETE"))
		{
			int pos, x; 
			scanf("%d %d", &pos, &x);
			int l = get_k(pos), r = get_k(pos + x + 1);
			splay(l, 0), splay(r, l);
			dfs(t[r].son[0]), t[r].son[0] = 0;
			push_up(r), push_up(l);
		}
		else if(!strcmp(opt, "MAKE-SAME"))
		{
			int pos, x, c; 
			scanf("%d %d %d", &pos, &x, &c);
			int l = get_k(pos), r = get_k(pos + x + 1);
			splay(l, 0), splay(r, l);
			
			tree &u = t[t[r].son[0]];
			u.val = c, u.sum = c * u.siz, u.ls = u.rs = max(0, u.sum);
			u.ms = max(c, u.sum), u.al = 1;
			push_up(r), push_up(l);
		}
		else if(!strcmp(opt, "REVERSE"))
		{
			int pos, x; 
			scanf("%d %d", &pos, &x);
			int l = get_k(pos), r = get_k(pos + x + 1);
			splay(l, 0), splay(r, l);
			tree &u = t[t[r].son[0]];
			u.rev ^= 1;
			swap(u.ls, u.rs), swap(u.son[0], u.son[1]);
			push_up(r), push_up(l);
		}
		else if(!strcmp(opt, "GET-SUM"))
		{
			int pos, x; 
			scanf("%d %d", &pos, &x);
			int l = get_k(pos), r = get_k(pos + x + 1);
			splay(l, 0), splay(r, l);
			push_up(r), push_up(l);
			printf("%d\n", t[t[r].son[0]].sum);	
		} 
		else if(!strcmp(opt, "MAX-SUM"))
		{
			printf("%d\n", t[rt].ms);
		}
	}
	return 0;
}

posted @ 2025-02-13 10:41  Helioca  阅读(12)  评论(0)    收藏  举报
Document