Bzoj P3224 [Tyvj1728]普通平衡树___splay

6 篇文章 0 订阅

题目大意:

您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:

  1. 插入x数
  2. 删除x数(若有多个相同的数,因只删除一个)
  3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
  4. 查询排名为x的数
  5. 求x的前驱(前驱定义为小于x,且最大的数)
  6. 求x的后继(后继定义为大于x,且最小的数)
    . n < = 100000 n<=100000 n<=100000
    每 个 数 的 数 据 范 围 : [ − 2 e 9 , 2 e 9 ] 每个数的数据范围:[-2e9,2e9] [2e9,2e9]

分析:

之前用treap做过这一道题,
现在学了一发splay,就顺便用splay写一发练下手
splay主要特点就是
每次操作都会将操作的点旋转到根,比较treap的话就不会有那么大的随机性
但不会保证树一直是平衡的,
可是各种操作的平摊时间复杂度是O(log n)
可参考的优质博客:
https://blog.csdn.net/clove_unique/article/details/50630280

代码:

#pragma GCC optimize(2)
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstdlib>
#include <algorithm>


#define rep(i, st, ed) for (int i = st; i <= ed; i++)
#define rwp(i, ed, st) for (int i = ed; i >= st; i--)
#define N 1000005

using namespace std;

int son[N][2], size[N], cnt[N], key[N], f[N];
int root, tot, n;

void clear(int x)
{
	son[x][0] = son[x][1] = size[x] = cnt[x] = key[x] = f[x] = 0;
}

bool get(int x)
{
	return son[f[x]][1] == x;
}

void update(int x)
{
	if (x) { size[x] = cnt[x] + (son[x][0] ? size[son[x][0]] : 0) + (son[x][1] ? size[son[x][1]] : 0); }
}

void rotate(int x)
{
	int fa = f[x], fafa = f[fa], num = get(x);
	son[fa][num] = son[x][num^1]; f[son[fa][num]] = fa;
	son[x][num^1] = fa; f[fa] = x; f[x] = fafa;
	if (fafa) son[fafa][son[fafa][1] == fa] = x;
	update(fa); 
	update(x);
}

void splay(int x)
{
	int fa;
	for (; fa = f[x];)
	{
	    if (f[fa]) rotate((get(x) == get(fa) ? fa : x));
        rotate(x);
	}
	root = x;
}

void Ins(int x)
{
	if (!root) { root = ++tot, son[root][0] = son[root][1] = f[root] = 0, size[root] = cnt[root] = 1, key[root] = x; return; }
	int now = root, fa = 0;
	while (now)
	{
		if (x == key[now]) { cnt[now]++, update(now), update(fa), splay(now); break; }
	    fa = now;
		now = son[now][x > key[now]];
		if (!now)
		{
			tot++;
			son[tot][0] = son[tot][1] = 0, f[tot] = fa, size[tot] = cnt[tot] = 1, key[tot] = x;
			son[fa][x > key[fa]] = tot;
			update(fa); splay(tot);
		}
	}
}

int Get_numRank(int x)
{
	int now = root, ans = 0;
	while (now)
	{
		if (x < key[now]) now = son[now][0];
		else
		{
			ans += (son[now][0] ? size[son[now][0]] : 0);
			if (x == key[now]) { splay(now); return ans + 1; }
			ans += cnt[now]; now = son[now][1];
		}
	} 
	return 0; 
}

int Get_Ranknum(int x)
{
	int now = root;
	while (now)
	{
		int cdp = (son[now][0] ? size[son[now][0]] : 0);
		if (x <= cdp) now = son[now][0];
		else
		{
			if (x <= cdp + cnt[now]) return key[now];
			x -= (cdp + cnt[now]); 
			now = son[now][1];
		}
	}
	return 0;
}

int Get_Pre()
{
	int now = son[root][0];
	while (son[now][1]) now = son[now][1];
	return now;
}

int Get_Nxt()
{
	int now = son[root][1];
	while (son[now][0]) now = son[now][0];
	return now;
}

void Del(int x)
{
	int fa, newroot;
	Get_numRank(x); //root = x
	if (cnt[root] > 1) { cnt[root]--, size[root]--; return; }
	if (!son[root][0] && !son[root][1]) { clear(root); root = 0; return; }
	if (!son[root][0]) { fa = root, root = son[root][1], f[root] = 0, clear(fa); return; }
	if (!son[root][1]) { fa = root, root = son[root][0], f[root] = 0, clear(fa); return; }
	newroot = Get_Pre(), fa = root;
	splay(newroot); // root = newroot
	son[root][1] = son[fa][1], f[son[fa][1]] = root, clear(fa);
	update(root); 
}

int main()
{
	freopen("data.in", "r", stdin); 
	scanf("%d", &n);
	int opt, x;
	rep(i, 1, n)
	{
		scanf("%d %d", &opt, &x);
		if (opt == 1) Ins(x);
		if (opt == 2) Del(x); 
		if (opt == 3) printf("%d\n", Get_numRank(x));
		if (opt == 4) printf("%d\n", Get_Ranknum(x)); 
		if (opt == 5) { Ins(x); printf("%d\n", key[Get_Pre()]); Del(x); }
	    if (opt == 6) { Ins(x); printf("%d\n", key[Get_Nxt()]); Del(x); } 
	}
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值