左偏树

思想

这是一种支持合并操作的堆,实现起来很简单

对于每一个节点,拥有一个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);
} 

 

posted @ 2017-11-25 00:43  尹吴潇  阅读(145)  评论(0编辑  收藏  举报