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

视频链接:236 左偏树 可并堆【模板】_哔哩哔哩_bilibili

 

 

 

 

 

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

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=1e5+10;
int v[N],lc[N],rc[N],dis[N]; //左偏树
int fa[N]; //并查集

int find(int x){ //并查集找根
  return x==fa[x] ? x : fa[x]=find(fa[x]);
}
int merge(int x,int y){
  if(!x||!y) return x+y; //若一个堆为空则返回另一个堆
  if(v[x]==v[y] ? x>y : v[x]>v[y]) swap(x,y); //取小值做根
  rc[x]=merge(rc[x],y); //递归合并右儿子与另一个堆
  
  if(dis[lc[x]]<dis[rc[x]]) swap(lc[x],rc[x]); //维护左偏性
  dis[x]=dis[rc[x]]+1;  //更新dis
  return x; //返回合并后的根
}
int main(){
  int n,m; scanf("%d%d",&n,&m);
  for(int i=1; i<=n; i++) scanf("%d",&v[i]);
  for(int i=1; i<=n; i++) fa[i]=i;
  dis[0]=-1; //空节点的dis初始化
  for(int op,x,y; m; m--){
    scanf("%d",&op);
    if(op==1){ //合并堆
      scanf("%d%d",&x,&y);
      if(v[x]==-1 || v[y]==-1) continue;
      x=find(x), y=find(y);
      if(x!=y) fa[x]=fa[y]=merge(x,y);
    }
    else{ //删除堆顶
      scanf("%d",&x);
      if(v[x]==-1){printf("-1\n"); continue;}
      x=find(x);
      printf("%d\n",v[x]);
      v[x]=-1; //删除标记
      fa[lc[x]]=fa[rc[x]]=fa[x]=merge(lc[x],rc[x]);
    }
  }
}

 

练习:

Luogu P2713 罗马游戏

Luogu P1456 Monkey King

 

posted @ 2023-07-07 22:22  董晓  阅读(271)  评论(0编辑  收藏  举报