Loading

可并堆

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

题意:

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

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

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

思路1:可并堆

时间复杂度 \(O(n\log n)\)

#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(n\log n \log n)\) 跑得飞快

#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());
		}
	}
}
posted @ 2022-07-11 09:49  Into_qwq  阅读(30)  评论(0编辑  收藏  举报