P3377 【模板】左偏树(可并堆)

本文详细介绍了左偏树的性质、操作方法以及其实现,包括插入、查询、删除和合并等操作。通过递归合并实现左偏树的合并,并在C++中给出具体代码实现。文章还涉及到了左偏树在数据集合并过程中的O(logn)时间复杂度,以及在解决最值查找问题上的应用。
摘要由CSDN通过智能技术生成

题目

题目

思路

显然左偏树板子。
所谓左偏树,就是具有左偏性质的二叉树,主要操作有:

  1. 在指定集合插入一个元素
  2. 查询指定集合最…的元素
  3. 删除指定集合最…的元素
  4. 删除给定下标的元素
  5. 合并2个集合

注意,这里的合并操作是O(logn)
具体怎么做呢?首先,树该有的左右儿子,键值,父亲节点都要有。
同时我们定义 d i s i dis_i disii到其子节点的最近叶节点的距离
那么左偏树满足:

  1. 键值有序
  2. 左子节点距离>=右子节点距离

左偏树合并使用递归完成。
显然,A,B合并,边界情况即其一为空,不妨设B为空,则返回A即可。
否则,不妨设A的根键值<B的根键值,小根堆即要將A的根作为根,然后即合并r(A),B
注意,合并之后如果r(A)>l(A)(指距离),交换左右。
还有,更新A的根的距离。
code:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<cstring>
#include<cmath>
#include<queue>
#include<deque>
using namespace std;
//When I wrote this code,God and I unterstood what was I doing 
int tree[2000005],r[2000005],l[2000005],dis[2000005],fa[2000005],del[2000005];
int MG(int a,int b)
{
	if (!a) return b;
	if (!b) return a;
	if (tree[a]>tree[b]) swap(a,b);
	r[a]=MG(r[a],b);
	if (dis[r[a]]>dis[l[a]]) swap(l[a],r[a]);
	if (!r[a]) dis[a]=0;
	else dis[a]=dis[r[a]]+1;
	return a;
}
void build(int n)
{
	int head[2000005],r=n,hb=1;
	for (int i=1;i<=n;i++) head[i]=i;
	for (int i=1;i<n;i++)
	{
		int root=MG(head[hb],head[hb+1]);
		r++;
		head[r]=root;
		hb+=2;
	}
	return;
}
void Del(int x)
{
	del[x]=1;
	fa[x]=fa[l[x]]=fa[r[x]]=MG(l[x],r[x]);
	l[x]=r[x]=dis[x]=0;
	return;
}
int find(int x)
{
	if (x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}
int n,m;
int main()
{
	cin>>n>>m;
	for (int i=1;i<=n;i++) cin>>tree[i],fa[i]=i;
	for (int i=1;i<=m;i++)
	{
		int opt;
		cin>>opt;
		if (opt==1)
		{
			int x,y;
			cin>>x>>y;
            if(del[x]||del[y]) continue;
			x=find(x),y=find(y);
			if (x!=y) fa[x]=fa[y]=MG(x,y);
		}
		else
		{
			int x;
			cin>>x;
			if (del[x])
			{
				printf("-1\n");
				continue;
			}
			x=find(x);
			cout<<tree[x]<<endl;
			Del(x);
		}
	}
    return 0;
}
//Now,only God know
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值