[模板]左偏树

用途

可在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 }

 

posted @ 2019-03-06 20:27  Ressed  阅读(147)  评论(0编辑  收藏  举报