zoukankan      html  css  js  c++  java
  • [模板]左偏树

    用途

    可在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
    ",-1);
    58             else printf("%d
    ",pop(getf(x)));
    59         }
    60     }
    61     return 0;
    62 }
  • 相关阅读:
    编译Android源码
    Android Studio 更新
    ANDROID:替换系统桌面
    Linux目录树与文件系统
    主引导记录MBR
    Android开发使用run-as获取应用数据
    桥接模式
    工厂方法模式
    Floyd's Cycle Detection Algorithm
    用两个stack实现一个队列
  • 原文地址:https://www.cnblogs.com/Ressed/p/10485765.html
Copyright © 2011-2022 走看看