<span>平衡树模板——splay,treap</span>

splay

https://blog.csdn.net/clove_unique/article/details/50636361

treap

思维纲要:https://mubu.com/doc/w10-lxTDU0

what's heap in treap?

assign a random number to any new node in order to prevent its complexity from degenerating due to a sequence of ordered numbers to be inserted

how to make heap?

everytime we insert or delete, just keep the randomly assigned number in heap's order

//reference:https://blog.csdn.net/Emm_Titan/article/details/103246344

#include <bits/stdc++.h>	
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e6+10;//larger
int num=0;//the number of the nodes
int cnt[maxn];//the number of this node
int key[maxn];//value
int ran[maxn];//random value,               and we declare that the deeper the tree, the larger the node's ran'value will be
int siz[maxn];//the number of its sons
int son[maxn][2];//left right son
void pushup(int x)
{
	siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x];
}
void rotate(int &x,int op)//mark op=0,1-->left right rotate    
{
	int p=son[x][!op];//save the heir
	son[x][!op]=son[p][op];
	son[p][op]=x;
	pushup(x);//pushup the new son first
	pushup(p);
	x=p;//                               that's cool,because we also need to update the new node(new father)'s father,so we say p is the new x(p succeed x).and because "rotate" always company with "insert(son[k][op],x);" etc., so son[k][op] can be update。 
}							
void my_insert(int &k,int x)//&k:when successfully insert a new node,update it after recursion
{
	if (k==0)
	{
		k=++num;		
		cnt[k]=1;
		key[k]=x;
		ran[k]=rand();
		siz[k]=1;
		return;
	}
	else if (key[k]==x)
	{
		cnt[k]++;
		siz[k]++;
		return;
	}
	int op=(x>key[k]);//to its left right son
	my_insert(son[k][op],x);
	if (ran[son[k][op]]<ran[k]) rotate(k,!op);//rotate from the the other size
	pushup(k);	
}
void my_delete(int &k,int x)
{
	if (k==0) return;//this "x" does not exist
	if (x!=key[k])
	{
		int op=(x>key[k]);
		my_delete(son[k][op],x);
		pushup(k);
		/* TODO (#4#): no matter what, all need to pushup */
		
		return;
	}
	//if x==key[k]----means we get it
	if (cnt[k]>1)
	{
		cnt[k]--;
		siz[k]--;
		pushup(k);
		/* TODO (#2#): forget to pushup */
				
		return;
	}
	if (!son[k][0]&&son[k][1])
	{
		rotate(k,0);//only have right son,so we can only choose left rotate 
		my_delete(son[k][0],x);
	}
	else if (son[k][0]&&!son[k][1])
	{
		rotate(k,1);
		my_delete(son[k][1],x);		
	}
	else if (!son[k][0]&&!son[k][1])
	{
		cnt[k]--;
		siz[k]--;
		if (cnt[k]==0) k=0;
		/* TODO (#3#): directly delete whole note */
		
	}
	else
	{
		int op=(ran[son[k][0]]>ran[son[k][1]]);//if left son's ran'val is larger,we can only choose left rotate,or we break the ran'val rule
		rotate(k,!op);
		my_delete(son[k][!op],x);	
			/* TODO (#1#): (!)op */	
					
	}
	pushup(k);	
}
int my_find(int k,int x)//find key whose rank is x
{
	if (k==0) return 0;
	if (siz[son[k][0]]>=x) return my_find(son[k][0],x);
	else if (siz[son[k][0]]+cnt[k]<x)return my_find(son[k][1],x-siz[son[k][0]]-cnt[k]);
	else return key[k];
}
int my_rank(int k,int x)//find the key's rank
{
	if (k==0) return 0;
	if (key[k]==x) return siz[son[k][0]]+1;
	if (key[k]>x) return my_rank(son[k][0],x);
	return siz[son[k][0]]+cnt[k]+my_rank(son[k][1],x);
}
int my_lowerbound(int k,int x)
{
	if (k==0) return -inf;
	if (key[k]>=x) return my_lowerbound(son[k][0],x);
	else return max(key[k],my_lowerbound(son[k][1],x));
}
int my_upperbound(int k,int x)
{
	if (k==0) return inf;
	if (key[k]<=x) return my_upperbound(son[k][1],x);
	else return min(key[k],my_upperbound(son[k][0],x));
}
int main()
{
//	freopen("t.txt","r",stdin);
	int n;
	cin>>n;
	memset(son,0,sizeof(son));
	int root=0;
	while (n--)
	{
		int opt,x;
		scanf("%d%d",&opt,&x);
		switch(opt)
		{
			case 1:my_insert(root,x);break;
			case 2:my_delete(root,x);break;
			case 3:printf("%d\n",my_rank(root,x));break;
			case 4:printf("%d\n",my_find(root,x));break;
			case 5:printf("%d\n",my_lowerbound(root,x));break;
			case 6:printf("%d\n",my_upperbound(root,x));break;
			default:break;
		}
	}	
//	fclose(stdin);
	return 0;

}
全部评论

相关推荐

04-02 10:09
门头沟学院 Java
用微笑面对困难:这里面问题还是很多的,我也不清楚为啥大家会感觉没啥问题。首先就是全栈开发实习9个月的内容都没有java实习生的内容多,1整个技术栈没看出太核心和难点的内容,感觉好像被拉过去打杂了,而且全栈基本上很容易被毙。里面能问的bug是在太多了比如L:继承 BaseMapper 可直接使用内置方法’。请问你的 BaseMapper 是如何扫描实体类注解如果瞬时产生 100 个上传任务,MySQL 的索引设计是否会有瓶颈?你做过分库分表或者索引优化吗?全栈的内容可以针对动态难点去搞,技能特长写在下面吧,你写了这么多技能,项目和实习体现了多少?你可以在项目里多做文章然后把这个放下去,从大致来看实习不算太水,有含金量你也要写上内容针对哨兵里面的节点变化能问出一万个问题,这个很容易就爆了。
提前批简历挂麻了怎么办
点赞 评论 收藏
分享
上周组里招人,我面了六个候选人,回来跟同事吃饭的时候聊起一个让我挺感慨的现象。前三个候选人,算法题写得都不错。第一道二分查找,五分钟之内给出解法,边界条件也处理得干净。第二道动态规划,状态转移方程写对了,空间复杂度也优化了一版。我翻他们的简历,力扣刷题量都在300以上。后三个呢,就有点参差不齐了。有的边界条件没处理好,有的直接说这道题没刷过能不能换个思路讲讲。其中有一个女生,我印象特别深——她拿到题之后没有马上写,而是先问我:“面试官,我能先跟你确认一下我对题目的理解吗?”然后她把自己的思路讲了一遍,虽然最后代码写得不是最优解,但整个沟通过程非常顺畅。这个女生的代码不是最优的,但当我问她“如果这里是线上环境,你会怎么设计’的时候,她给我讲了一套完整的方案——异常怎么处理、日志怎么打、怎么平滑发布。她对这是之前在实习的时候踩过的坑。”我在想LeetCode到底在筛选什么?我自己的经历可能有点代表性。我当年校招的时候,也是刷了三百多道题才敢去面试。那时候大家都刷,你不刷就过不了笔试关。后来工作了,前三年基本没再打开过力扣。真正干活的时候,没人让你写反转链表,也没人让你手撕红黑树。更多的是:这个接口为什么慢了、那个服务为什么OOM了、线上数据对不上了得排查一下。所以后来我当面试官,慢慢调整了自己的评判标准。算法题我还会出,但目的变了。我出算法题,不是想看你能不能背出最优解。而是想看你拿到一个陌生问题的时候,是怎么思考的。你会先理清题意吗?你会主动问边界条件吗?你想不出来的时候会怎么办?你写出来的代码,变量命名乱不乱、结构清不清楚?这些才是工作中真正用得到的能力。LeetCode是一个工具,不是目的。它帮你熟悉数据结构和常见算法思路,这没问题。但如果你刷了三百道题,却说不清楚自己的项目解决了什么问题、遇到了什么困难、你是怎么解决的,那这三百道题可能真的白刷了。所以还要不要刷LeetCode?要刷,但别只刷题。刷题的时候,多问自己几个为什么:为什么用这个数据结构?为什么这个解法比那个好?如果换个条件,解法还成立吗?把刷题当成锻炼思维的方式,而不是背答案的任务。毕竟面试官想看到的,从来不是一台背题机器,而是一个能解决问题的人。
国企上岸了的向宇同桌...:最害怕答非所问了,但是频繁反问确定意思又害怕面试官觉得我笨
AI时代还有必要刷lee...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务