1. 程式人生 > >[模板]左偏樹

[模板]左偏樹

spa 更新 fine typedef har 是把 color getchar() 中比

用途

可在log復雜度合並的堆

性質

每個節點有一個距離,具體定義我不知道

1.滿足堆的性質

2.左子節點距離>=右子節點

3.節點距離=右子節點距離加1

實現

按照以上的性質實現merge(x,y),先選出x,y中比較大的那個(大根堆為例),再拿它的右兒子和另一個去merge,如果merge出來不符合性質2就swap一下,最後更新自己的距離

於是也能實現pop,就是把根節點的左右孩子merge起來

實現過程中只需要記孩子不需要記父親,但可以仿照並查集的樣子記父親來做到給一個點查它所屬的根

例題

luogu3377

一開始有N個小根堆,每個堆包含且僅包含一個數。接下來需要支持兩種操作:

操作1: 1 x y 將第x個數和第y個數所在的小根堆合並(若第x或第y個數已經被刪除或第x和第y個數在用一個堆內,則無視此操作)

操作2: 2 x 輸出第x個數所在的堆最小數,並將其刪除(若第x個數已經被刪除,則輸出-1並無視刪除操作)

 1 #include<bits/stdc++.h>
 2 #define pa pair<int,int>
 3 #define CLR(a,x) memset(a,x,sizeof(a))
 4 #define MP make_pair
 5 using namespace std;
 6 typedef long
long ll; 7 const int maxn=1e5+10; 8 9 inline char gc(){ 10 return getchar(); 11 static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf; 12 return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++; 13 } 14 inline ll rd(){ 15 ll x=0;char
c=gc();bool neg=0; 16 while(c<0||c>9){if(c==-) neg=1;c=gc();} 17 while(c>=0&&c<=9) x=(x<<1)+(x<<3)+c-0,c=gc(); 18 return neg?(~x+1):x; 19 } 20 21 int ch[maxn][2],fa[maxn],v[maxn],dis[maxn],N,M; 22 23 inline int getf(int x){ 24 while(fa[x]) x=fa[x];return x; 25 } 26 27 inline int merge(int x,int y){ 28 if(!x) return y; 29 if(!y) return x; 30 if(v[x]>v[y]||(v[x]==v[y]&&x>y)) swap(x,y); 31 ch[x][1]=merge(ch[x][1],y); 32 fa[ch[x][1]]=x; 33 if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][0],ch[x][1]); 34 dis[x]=dis[ch[x][1]]+1; 35 return x; 36 } 37 38 inline int pop(int x){ 39 int re=v[x];v[x]=-1; 40 fa[merge(ch[x][0],ch[x][1])]=0; 41 return re; 42 } 43 44 int main(){ 45 // freopen("testdata.in","r",stdin); 46 int i,j,k; 47 N=rd(),M=rd(); 48 for(i=1;i<=N;i++) v[i]=rd(); 49 for(i=1;i<=M;i++){ 50 int a=rd(),x=rd(); 51 if(a==1){ 52 int y=rd(); 53 if(v[x]==-1||v[y]==-1) continue; 54 x=getf(x),y=getf(y); 55 fa[merge(x,y)]=0; 56 }else{ 57 if(v[x]==-1) printf("%d\n",-1); 58 else printf("%d\n",pop(getf(x))); 59 } 60 } 61 return 0; 62 }

[模板]左偏樹