可并堆
P3377 【模板】左偏树(可并堆)#
题意:#
一开始有 个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作:
-
1 x y
:将第 个数和第 个数所在的小根堆合并(若第 或第 个数已经被删除或第 和第 个数在用一个堆内,则无视此操作)。 -
2 x
:输出第 个数所在的堆最小数,并将这个最小数删除(若有多个最小数,优先删除先输入的;若第 个数已经被删除,则输出 并无视删除操作)。
思路1:可并堆#
时间复杂度
#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: 按秩合并路径压缩并查集 启发式合并#
为什么要学习可并堆啊
我用 不香吗?
时间复杂度 跑得飞快
#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());
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现