BST - Binary Search Tree

容易发现对于插入 xx,如果我们找到了 xx 的前驱 pp 和后继 nn,那么 xx 一定位于 ppnn 的某个儿子上。

仔细观察,发现 xx 会位于 ppnn 中深度较大的一个的儿子上。

于是我们依次插入每个数,查前驱后继,并且更新深度。

然后可以直接用 set 做,然而我写了个 Splay,结果跑得比 set 还慢。

#pragma GCC optimize("-Ofast")
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#include <climits>
#include <string>
using namespace std;

const int N = 3e5 + 5;
long long dep[N];

class Splay
{
public:
	int rt, idx;
	struct Node
	{
		int son[2], fa, sz, cnt, val;
	}tr[N];
	void pushup(int u)
	{
		tr[u].sz = tr[tr[u].son[0]].sz + tr[tr[u].son[1]].sz + tr[u].cnt;
	}
	int get(int u)
	{
		return u == tr[tr[u].fa].son[1];
	}
	void rotate(int x)
	{
		int y = tr[x].fa, z = tr[y].fa;
		int chkx = get(x), chky = get(y);
		tr[y].son[chkx] = tr[x].son[chkx ^ 1];
		if (tr[x].son[chkx ^ 1]) tr[tr[x].son[chkx ^ 1]].fa = y;
		tr[x].son[chkx ^ 1] = y;
		tr[y].fa = x;
		tr[x].fa = z;
		if (z) tr[z].son[chky] = x;
		pushup(y);
		pushup(x);
	}
	void splay(int x)
	{
		for (int f = tr[x].fa; f = tr[x].fa, f; rotate(x))
		{
			if (tr[f].fa) rotate(get(f) == get(x) ? f : x);
		}
		rt = x;
	}
	void ins(int x)
	{
		if (!rt)
		{
			rt = ++idx;
			tr[rt].val = x;
			tr[rt].cnt = 1;
			pushup(rt);
			return;
		}
		int u = rt, f, last;
		while (true)
		{
			if (tr[u].val == x)
			{
				tr[u].cnt++;
				pushup(u);
				pushup(f);
				splay(u);
				return;
			}
			if (!u)
			{
				u = ++idx;
				tr[u].fa = f;
				tr[u].val = x;
				tr[u].cnt = 1;
				tr[f].son[last] = u;
				pushup(u);
				pushup(f);
				splay(u);
				return;
			}
			f = u;
			last = x > tr[u].val;
			u = tr[u].son[last];
		}
	}
	int rank(int k)
	{
		int res = 0, u = rt;
		while (true)
		{
			if (tr[u].val > k)
			{
				u = tr[u].son[0];
			}
			else if (tr[u].val == k)
			{
				res += tr[tr[u].son[0]].sz;
				splay(u);
				return res + 1;
			}
			else
			{
				res += tr[tr[u].son[0]].sz + tr[u].cnt;
				u = tr[u].son[1];
			}
		}
	}
	int pre()
	{
		int u = tr[rt].son[0];
		if (!u) return 0;
		while (tr[u].son[1]) u = tr[u].son[1];
		splay(u);
		return tr[u].val;
	}
	int nxt()
	{
		int u = tr[rt].son[1];
		if (!u) return 0;
		while (tr[u].son[0]) u = tr[u].son[0];
		splay(u);
		return tr[u].val;
	}
	void CLEAR(int u)
	{
		tr[u].cnt = tr[u].fa = tr[u].son[0] = tr[u].son[1] = tr[u].sz = tr[u].val = 0;
	}
	void del(int x)
	{
		rank(x);
		int u = rt;
		if (tr[u].cnt > 1)
		{
			tr[u].cnt--;
			pushup(u);
			return;
		}
		if (!tr[u].son[0])
		{
			tr[tr[u].son[1]].fa = 0;
			rt = tr[u].son[1];
			CLEAR(u);
			return;
		}
		if (!tr[u].son[1])
		{
			tr[tr[u].son[0]].fa = 0;
			rt = tr[u].son[0];
			CLEAR(u);
			return;
		}
		pre();
		tr[rt].son[1] = tr[u].son[1];
		tr[tr[u].son[1]].fa = rt;
		pushup(rt);
		CLEAR(u);
	}
}tr;

int n;
long long c;

int main()
{
	tr.ins(INT_MIN);
	tr.ins(INT_MAX);
	scanf("%d", &n);
	int rn = n;
	while (n--)
	{
		int x;
		scanf("%d", &x);
		long long tp = 0LL;
		tr.ins(x);
		if (n == rn - 1)
		{
			printf("%lld\n", c);
			continue;
		}
		int p = tr.pre();
		tr.rank(x);
		int nx = tr.nxt();
		if (p != INT_MIN)
		{
			tp = dep[p];
		}
		if (nx != INT_MAX)
		{
			tp = max(tp, dep[nx]);
		}
		dep[x] = tp + 1LL;
		c += tp + 1LL;
		printf("%lld\n", c);
	}
	return 0;
}
posted @   HappyBobb  阅读(3)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示