左偏树(可合并堆): 有时需要将两个堆合并,此时每次都对一个pop()再在另一个push() ,太慢了。此时直接合并堆会更快,设堆1有size1个节点,堆2有size2个节点,则合并堆1堆2的复杂度为: O ( l o g ( s i z e 1 ) ) + O ( l o g ( s i z e 2 ) ) O(log(size1))+O(log (size2)) O(log(size1))+O(log(size2))。
手写左偏树版:
#include<bits/stdc++.h>
#define ll long long
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define DEBUG cout<<",here\n";
#define Rep(i,l,r) for(int i=(l);i<=(r);i++)
#define rep(i,l,r) for(int i=(l);i< (r);i++)
#define Rev(i,r,l) for(int i=(r);i>=(l);i--)
#define rev(i,r,l) for(int i=(r);i> (l);i--)
#define MAXN 100005
using namespace std;
struct L_Tree
{
struct Node
{
int val;
int lc,rc,dis,par;
};
const static int maxn=MAXN;
Node t[maxn];
void init(int x){
for (int i = 1; i <= x; i++) {
t[i].lc = t[i].rc = t[i].dis = 0;
t[i].val=-1;
//并查集默认值0,不用特意修改
}
t[0].dis=-1;
}
//注意该并查集默认值为0
int find(int x){if(t[x].par==0)return x;return t[x].par=find(t[x].par);}
int join(int x, int y) {
if(!x||!y) return x+y;
if(t[x].val>t[y].val||(t[x].val==t[y].val&&x>y))//修改这里来适应大/小根堆
swap(x,y);
t[x].rc=join(t[x].rc,y);t[t[x].rc].par=x;
if(t[t[x].lc].dis<t[t[x].rc].dis)
swap(t[x].lc,t[x].rc);
t[x].dis=t[t[x].rc].dis+1;
return x;
}
void pop(int x){
t[x].val=-1;
t[t[x].lc].par=t[t[x].rc].par=0;
t[x].par=join(t[x].lc,t[x].rc);
}
};
int n,m;
L_Tree q;
int main()
{
cin>>n>>m;
q.init(n);
Rep(i,1,n){
int tmp;cin>>tmp;
q.t[i].val=tmp;
}
Rep(i,1,m){
int op;cin>>op;
if(op==1){
int x,y;cin>>x>>y;
if(q.t[x].val==-1||q.t[y].val==-1)continue;//被删除了
x=q.find(x),y=q.find(y);
if(x==y)continue;//已经在一个堆中
q.join(x,y);
}
else{
int x;cin>>x;
if(q.t[x].val==-1){cout<<"-1\n";continue;}//被删除了
x=q.find(x);
cout<<q.t[x].val<<"\n";
q.pop(x);
}
}
return 0;
}
pbds库版:
__gnu_pbds是gcc库里的,大多数用gcc编译器的oj都支持,用clang的加上后文代码前三行也行。
介绍:
定义:
#include <bits/stdc++.h>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef __gnu_pbds::priority_queue <pair<int, int>, greater<pair<int, int> >, pairing_heap_tag> heap;
heap q;
成员方法:
代码:
#ifdef __clang__
#define __builtin_sprintf sprintf
#endif
#include<bits/stdc++.h>
#include<bits/extc++.h>
#define ll long long
#define IOS std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define DEBUG cout<<",here\n";
#define Rep(i,l,r) for(int i=(l);i<=(r);i++)
#define rep(i,l,r) for(int i=(l);i< (r);i++)
#define Rev(i,r,l) for(int i=(r);i>=(l);i--)
#define rev(i,r,l) for(int i=(r);i> (l);i--)
using namespace std;
struct L_Tree
{
int v,id;
bool operator<(const L_Tree& bb)const{
if(v==bb.v)return id>bb.id;
return v>bb.v;
}
};
__gnu_pbds::priority_queue<L_Tree>q[100005];
int n,m;
int f[100005];
map<int,int>del;
int find(int x){if(f[x]==x)return x; return f[x]=find(f[x]);}
int main()
{
cin>>n>>m;
Rep(i,1,n){
int tmp;cin>>tmp;
q[i].push({tmp,i});
f[i]=i;
}
Rep(i,1,m){
int op;cin>>op;
if(op==1){
int x,y;cin>>x>>y;
if(del[x]||del[y])continue;
int fx=find(x),fy=find(y);
if(fx>fy)swap(fx,fy);
if(fx!=fy){
q[fx].join(q[fy]);//pbds库,合并堆
f[fy]=fx;
}
}
else{
int x;cin>>x;
if(del[x]==1){cout<<"-1\n";continue;}
x=find(x);
if(!q[x].empty()){
del[q[x].top().id]=1;
cout<<q[x].top().v<<"\n";
q[x].pop();
}
}
}
return 0;
}
参考:
左偏树模板
左偏树模板
pb_ds优先队列学习笔记