左偏树
思想
这是一种支持合并操作的堆,实现起来很简单
对于每一个节点,拥有一个dis值,即到儿子的最短距离
其具有左偏性质:左二子的dis值大于右儿子的dis值
由于此性质,保证了合并的时间复杂度是o(logn)的
每次合并时,沿着两个堆的右子树进行
每次合并其中一个的右子树和另外一个堆
代码
#include<bits/stdc++.h> const int maxn=300000; int v[maxn],fa[maxn],left1[maxn],right1[maxn],dis[maxn],id,xx,yy,x,y,n,m; using namespace std; int getfa(int x) { while (fa[x]!=0) x=fa[x]; return(x); }; int merge(int r1,int r2) { if (r1==0 or r2==0) return(r1+r2); if (v[r1]>v[r2] or v[r1]==v[r2] and r1>r2) swap(r1,r2); right1[r1]=merge(right1[r1],r2); fa[right1[r1]]=r1; if (dis[left1[r1]]<dis[right1[r1]]) swap(left1[r1],right1[r1]); dis[r1]=dis[right1[r1]]+1; return(r1); }; void delete1(int r1) { v[r1]=-1; fa[left1[r1]]=0; fa[right1[r1]]=0; merge(left1[r1],right1[r1]); }; int main(){ freopen("noip.in","r",stdin); freopen("noip.out","w",stdout); cin>>n>>m; for (int i=1; i<=n; i++) cin>>v[i]; for (int i=1; i<=m; i++){ cin>>id; if (id==1) { cin>>x>>y; if (v[x]==-1 or v[y]==-1) continue; xx=getfa(x); yy=getfa(y); if (xx!=yy) merge(xx,yy); } else { cin>>x; if (v[x]==-1) { cout<<"-1"<<endl; continue; } xx=getfa(x); cout<<v[xx]<<endl; delete1(xx); } } return(0); }