首页 > 其他分享 >FHQ-Treap

FHQ-Treap

时间:2024-08-21 14:05:04浏览次数:3  
标签:rt ch merge int Treap split now FHQ

全码
优点:码量短

写错了的话,\(TLE,MLE,Wa\)全家桶
包含合并操作

点击查看代码
#include <bits/stdc++.h>
#define speed() ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
#define ll long long
#define lid (rt<<1)
#define rid (rt<<1|1)
// #define endl '\n'
#define pii pair<int,int>
#define ull unsigned long long
#define pb push_back
#define ts cout<<"----------------"<<endl;
#define bs bitset<65>
using namespace std;
const int N = 1e6+5;
mt19937 rnd(chrono::system_clock::now().time_since_epoch().count());
int rand()
{
	uniform_int_distribution<ll>rg(LONG_LONG_MIN,LONG_LONG_MAX);
	return rg(rnd)%INT_MAX;
}
struct FHQ_Treap
{
	int ch[N][2],sz[N],rt,tot,id[N],v[N];
	inline void pushup(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;}
	inline int newnode(int x)
	{
		sz[++tot]=1;v[tot]=x;id[tot]=rand();
		return tot;
	}
	inline int merge(int x,int y)
	{
		if(!x||!y)return x^y;
		if(id[x]<id[y])return ch[x][1]=merge(ch[x][1],y),pushup(x),x;
		return ch[y][0]=merge(x,ch[y][0]),pushup(y),y;
	}
	inline void split(int now,int k,int &x,int &y)
	{
		if(!now)x=0,y=0;
		else
		{
			if(k>=v[now])x=now,split(ch[now][1],k,ch[now][1],y);
			else y=now,split(ch[now][0],k,x,ch[now][0]);
			pushup(now);
		}
	}
	inline void insert(int k)
	{
		int x,y;
		split(rt,k,x,y);
		rt=merge(merge(x,newnode(k)),y);
	}
	inline void del(int k)
	{
		int x,y,z;
		split(rt,k,x,y);
		split(x,k-1,x,z);//attention is x not rt
		z=merge(ch[z][0],ch[z][1]);rt=merge(merge(x,z),y);
	}
	inline int kth(int now,int k)
	{
		while(1)
		{
			if(k<=sz[ch[now][0]])now=ch[now][0];
			else if(k==sz[ch[now][0]]+1)return now;
			else k-=sz[ch[now][0]]+1,now=ch[now][1];
		}
	}
	inline int rank(int k)
	{
		int x,y;
		split(rt,k-1,x,y);int ans=sz[x]+1;
		return rt=merge(x,y),ans;
	}
	inline int pre(int k)
	{
		int x,y,ans;
		split(rt,k-1,x,y);
		ans=v[kth(x,sz[x])];
		return rt=merge(x,y),ans;
	}
	inline int nxt(int k)
	{
		int x,y,ans;
		split(rt,k,x,y);
		ans=v[kth(y,1)];
		return rt=merge(x,y),ans;
	}
}tree;
int n;
int main()
{
	speed();
	freopen("in.in","r",stdin);
	freopen("out.out","w",stdout);
	cin>>n;
	int opt,x;
	for(int i=1;i<=n;i++)
	{
		cin>>opt>>x;
		if(opt==1)
		{
			tree.insert(x);
		}else if(opt==2)
		{
			tree.del(x);
		}else if(opt==3)
		{
			cout<<tree.rank(x)<<endl;
		}else if(opt==4)
		{
			cout<<tree.v[tree.kth(tree.rt,x)]<<endl;
		}else if(opt==5)
		{
			cout<<tree.pre(x)<<endl;
		}else
		{
			cout<<tree.nxt(x)<<endl;
		}
	}
	return 0;
}

核心函数是合并和分离,所以都是基于\(rand\)维护
合并
格外要注意的是合并\(x\)和\(y\)要保证\(x\)中的所有元素都小于\(y\)中的,这里采用\(id\)小的在上面

	int merge(int x,int y)
	{
		if(!x||!y)return x^y;//返回非0项
		if(id[x]<id[y])return ch[x][1]=merge(ch[x][1],y),up(x),x;
		return ch[y][0]=merge(x,ch[y][0]),up(y),y;
	}

分裂操作,递归分裂,注意细节
注意\(x\)包含\(k\),\(y\)不包含\(k\)

	inline void split(int now,int k,int &x,int &y)
	{
		if(!now)x=0,y=0;
		else
		{
			if(k>=v[now])x=now,split(ch[now][1],k,ch[now][1],y);//一定要记得更新x,y
			else y=now,split(ch[now][0],k,x,ch[now][0]);//一定要记得更新x,y
			pushup(now);
		}
	}

插入,删除

	inline void insert(int k)
	{
		int x,y;
		split(rt,k,x,y);
		rt=merge(merge(x,newnode(k)),y);
	}
	inline void del(int k)
	{
		int x,y,z;
		split(rt,k,x,y);
		split(x,k-1,x,z);//attention is x not rt
		z=merge(ch[z][0],ch[z][1]);rt=merge(merge(x,z),y);
	}

查询第\(k\)小

	inline int kth(int now,int k)
	{
		while(1)
		{
			if(k<=sz[ch[now][0]])now=ch[now][0];
			else if(k==sz[ch[now][0]]+1)return now;
			else k-=sz[ch[now][0]]+1,now=ch[now][1];
		}
	}

查询权值的排名

	inline int rank(int k)
	{
		int x,y;
		split(rt,k-1,x,y);int ans=sz[x]+1;
		return rt=merge(x,y),ans;
	}

查询前驱,后继

	inline int pre(int k)
	{
		int x,y,ans;
		split(rt,k-1,x,y);
		ans=v[kth(x,sz[x])];
		return rt=merge(x,y),ans;
	}
	inline int nxt(int k)
	{
		int x,y,ans;
		split(rt,k,x,y);
		ans=v[kth(y,1)];
		return rt=merge(x,y),ans;
	}

标签:rt,ch,merge,int,Treap,split,now,FHQ
From: https://www.cnblogs.com/wlesq/p/18304855

相关文章

  • 随用随取的无旋Treap板子!
    使用说明及注意事项:使用命名空间+结构体进行封装,使用时只需jser::Treap或usingnamespacejser即可。例如:/*way1*/usingnamespacejser;Treaptree;/*way2*/jser::Treaptree;随机数生成采用random_device和mt19937,在某些评测姬上可能不适用,可以换用rand(注意数......
  • 「FHQ-Treap —— 码量最小的平衡树」学习笔记
    不同于普通Treap,FHQ-Treap不需要左旋和右旋操作来处理数据。因此FHQ-Treap也称作无旋Treap。FHQ-Treap是基于Split(分裂)和Merge(合并)两种操作的平衡树。其与普通Treap的原理完全不同。一些基础的操作:例如Insert(插入元素)和Delete(删除元素)。对于Insert(插入元素),新建一......
  • 怎么优雅的踩爆 Treap
    在发布了文章Treap学习笔记后我认为我的平衡树能力已经登峰造极了。但是Treap真tmd太难写了,所以我们的czy大佬开发除了一种可以优雅的踩爆Treap的绝佳方案。#include<bits/stdc++.h>usingnamespacestd;intn;structtree{ vector<int>v; voidadd(intx){v.in......
  • FHQ_Treap
    先记个板子#include<bits/stdc++.h>usingnamespacestd;constintN=1e5+5;intn;intrt,son[N][2],sz[N],va[N],pri[N],tot;structFHQ{ voidpushup(intx){sz[x]=sz[son[x][0]]+sz[son[x][1]]+1;} intmerge(intx,inty) { if(!x||!y)returnx|y; if......
  • FHQ treap(再见splay------)
    但凡打过平衡树的应该都知道\(\huge{二逼平衡树}\)这道题,抄了两个小时的splay版题解,然后发现了\(\color{maroon}FHQtreap\):$\large\color{green}这是splay$structjjtree{ inlinevoidup(rintx){sz[x]=sz[son[x][0]]+sz[son[x][1]]+cnt[x];} inlineboolso(rintx){retu......
  • 平衡樹專題Treap
    前言:题单在此:HL平衡树0701-题单-洛谷|计算机科学教育新生态(luogu.com.cn)平衡树什么是平衡树?首先我们需要知道二叉查找树的内容。二叉查找树(BST:BinarySearchTree)首先,他是一棵二叉树其次,他的左子树的权值<根节点的权值<右子树的权值最后,也是最重要的,他的中序遍历......
  • 算法课程笔记——FHQ-Treap(无旋)
    算法课程笔记——FHQ-Treap(无旋)......
  • 平衡树 Treap & Splay [学习笔记]
    平衡树\(\tt{Treap}\)&\(\tt{Splay}\)壹.单旋\(\tt{Treap}\)首先了解\(\tt{BST}\)非常好用的东西,但是数据可以把它卡成一条链\(\dots\)于是,我们将\(\tt{Tree}\)与\(\tt{heap}\)(堆)合并,以保证平衡树\(\log\)的深度。具体地,我们可以使用旋转操作实现K8He的图......
  • 平衡树 Treap & Splay [学习笔记]
    平衡树\(\tt{Treap}\)&\(\tt{Splay}\)壹.单旋\(\tt{Treap}\)首先了解\(\tt{BST}\)非常好用的东西,但是数据可以把它卡成一条链\(\dots\)于是,我们将\(\tt{Tree}\)与\(\tt{heap}\)(堆)合并,以保证平衡树\(\log\)的深度。具体地,我们可以使用旋转操作实现K8He的图......
  • 【老鼠看不懂的数据结构】FHQTreap 初识
    Treap弱平衡的随机性很强的老鼠看不懂的平衡树Q:为什么叫Treap?A:看看二叉搜索树(BST)和堆(Heap),组合起来就是Treap其中,二叉搜索树的性质是:左子节点的值(val)比父节点小右子节点的值(val)比父节点大如果这些节点的值都一样,这棵树就会退化成一颗(?)链。对,我知道你在想......