可并堆

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

题意:#

一开始有 n 个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作:

  1. 1 x y:将第 x 个数和第 y 个数所在的小根堆合并(若第 x 或第 y 个数已经被删除或第 x 和第 y 个数在用一个堆内,则无视此操作)。

  2. 2 x:输出第 x 个数所在的堆最小数,并将这个最小数删除(若有多个最小数,优先删除先输入的;若第 x 个数已经被删除,则输出 1 并无视删除操作)。

思路1:可并堆#

时间复杂度 O(nlogn)

#include<bits/stdc++.h>
using namespace std;

#define size asjhidj
#define def register auto

const int N=1e5+5;

inline int read(){
	def x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}

multiset <int> s[N];

int f[N],size[N],d[N];
bool isdel[N];
int ls[N],rs[N],h[N];
int n,m;


inline int getf(int x){
	return x==f[x]?x:f[x]=getf(f[x]);
}

namespace H{
	inline int Merge(int x,int y){
		if(!x) return y;
		if(!y) return x;
		if((h[x]==h[y]&&x>y)||h[x]>h[y]) swap(x,y);
		rs[x]=Merge(rs[x],y);
		if(d[ls[x]]<d[rs[x]]) swap(ls[x],rs[x]);
		f[ls[x]]=f[rs[x]]=f[x]=x;
		d[x]=d[rs[x]]+1;
		return x;
	}
	
	inline void pop(int x){
		isdel[x]=1;
		f[ls[x]]=ls[x];
		f[rs[x]]=rs[x];
		f[x]=Merge(ls[x],rs[x]);
	}
}



signed main(){
	n=read(),m=read();
	for(def i=1;i<=n;++i) f[i]=i;
	for(def i=1;i<=n;++i) h[i]=read();
	for(def i=1;i<=m;++i){
		def op=read();
		if(op==1){
			def x=read(),y=read();
			if(isdel[x]||isdel[y]) continue;
			def fx=getf(x),fy=getf(y);
			if(fx!=fy) f[fx]=f[fy]=H::Merge(fx,fy);
		}
		else{
			def x=read();
			if(isdel[x]){
				puts("-1");
				continue;
			}
			def fx=getf(x);
			printf("%d\n",h[fx]);
			H::pop(fx);
		}
	}
	return 0;
}

然而这不是我想要的

思路2:multiset + 按秩合并路径压缩并查集 + 启发式合并#

为什么要学习可并堆啊 qwq

我用 STL 不香吗?

时间复杂度 O(nlognlogn) 跑得飞快

#include<bits/stdc++.h>
using namespace std;

#define def register auto

const int N=1e5+5;

inline int read(){
	def x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch)){
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(isdigit(ch)){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*f;
}

struct node{
	int x,id;
	inline bool operator < (const node X) const{
		return x==X.x?id<X.id:x<X.x;
	}
}a[N];

int f[N],sz[N];
bool isdel[N];
int n,m;
multiset <node> s[N];

inline int getf(int x){
	return x==f[x]?x:f[x]=getf(f[x]);
}

signed main(){
	n=read(),m=read();
	for(def i=1;i<=n;++i){
		a[i].x=read();
		a[i].id=f[i]=i;
		sz[i]=1;
		s[i].insert(a[i]);
	}
	for(def i=1;i<=m;++i){
		def op=read();
		if(op==1){
			def x=read(),y=read();
			if(isdel[x]||isdel[y]) continue;
			int fx=getf(x),fy=getf(y);
			if(fx==fy) continue;
			if(sz[fx]<sz[fy]) swap(fx,fy);
			s[fx].insert(s[fy].begin(),s[fy].end());
			s[fy].clear();
			sz[fx]+=sz[fy];
			f[fy]=fx;
		}
		else{
			def x=read();
			if(isdel[x]){
				puts("-1");
				continue;
			}
			def fx=getf(x);
			def y=*s[fx].begin();
			--sz[fx];
			isdel[y.id]=1;
			cout<<y.x<<endl;
			s[fx].erase(s[fx].begin());
		}
	}
}

作者:Into_qwq

出处:https://www.cnblogs.com/into-qwq/p/16465428.html

版权:本作品采用「qwq」许可协议进行许可。

posted @   Into_qwq  阅读(35)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示