首页 > 其他分享 >左偏树

左偏树

时间:2023-07-05 23:01:27浏览次数:28  
标签:rs int fa MAXN ls heap 左偏

模板:

 

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
int n, m, heap[MAXN];
int fa[MAXN], ls[MAXN], rs[MAXN], dis[MAXN];
bool del[MAXN];

int find(int x) {
     return x == fa[x] ? x : fa[x] = find(fa[x]);
}

int Merge(int u, int v) {
    if(!u || !v) return u+v;
    if(heap[u]==heap[v]? u>v :heap[u]>heap[v]) swap(u,v);//相等比较u和V,否则比较heap[u]和heap[v] 
    rs[u]=Merge(rs[u],v);
    if(dis[rs[u]] > dis[ls[u]])  swap(ls[u],rs[u]);
    dis[u]=dis[rs[u]]+1;
    fa[ls[u]]=fa[rs[u]]=u;
    return u;
     
}

void pop(int u) {
    del[u]=true;
    fa[rs[u]]=rs[u];
    fa[ls[u]]=ls[u];
    fa[u]=Merge(ls[u],rs[u]);
   
}

void init() {
    for(int i=1;i<=n;i++){
        fa[i]=i;
    }
    
}

P3377:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 10;
int n, m, heap[MAXN];
int fa[MAXN], ls[MAXN], rs[MAXN], dis[MAXN];
bool del[MAXN];

int find(int x) {
     return x == fa[x] ? x : fa[x] = find(fa[x]);
}

int Merge(int u, int v) {
    if(!u || !v) return u+v;
    if(heap[u]==heap[v]? u>v :heap[u]>heap[v]) swap(u,v);//相等比较u和V,否则比较heap[u]和heap[v] 
    rs[u]=Merge(rs[u],v);
    if(dis[rs[u]] > dis[ls[u]])  swap(ls[u],rs[u]);
    dis[u]=dis[rs[u]]+1;
    fa[ls[u]]=fa[rs[u]]=u;
    return u;
     
}

void pop(int u) {
    del[u]=true;
    fa[rs[u]]=rs[u];
    fa[ls[u]]=ls[u];
    fa[u]=Merge(ls[u],rs[u]);
   
}

void init() {
    for(int i=1;i<=n;i++){
        fa[i]=i;
    }
    
}


int main() {
    dis[0] = -1;
    // 注意!此处是为了保证叶子节点 dis = 0
    scanf("%d %d", &n, &m);
    init();
    for (int i = 1; i <= n; i++)
        scanf("%d", &heap[i]);
    for (int opt, x, y; m; m--) {
        scanf("%d", &opt);
        if (opt == 1) {
            scanf("%d %d", &x, &y);
            if (del[x] || del[y])
                continue;//返回for循环 
            x = find(x), y = find(y);
            if (x != y) 
                fa[x] = fa[y] = Merge(x, y);
        } else {
            scanf("%d", &x);
            if (del[x]) {
                printf("-1\n");
                continue;
            }
            x = find(x);
            printf("%d\n", heap[x]);
            pop(x);
        }
    }
    return 0;
}

P1456:

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100010;
int n, m, heap[MAXN];
int fa[MAXN], ls[MAXN], rs[MAXN], dis[MAXN];

int find(int x) {
     return x == fa[x] ? x : fa[x] = find(fa[x]);
}

int Merge(int u, int v) {
    if(!u || !v) return u+v;
    if(heap[u]<heap[v]) swap(u,v);//相等比较u和V,否则比较heap[u]和heap[v] 
    rs[u]=Merge(rs[u],v);
    if(dis[rs[u]] > dis[ls[u]])  swap(ls[u],rs[u]);
    dis[u]=dis[rs[u]]+1;
    fa[ls[u]]=fa[rs[u]]=u;
    return u;
     
}


void init() {
    for(int i=1;i<=n;i++){
        ls[i]=rs[i]=dis[i]=0;
        fa[i]=i;
    }
    
}

int main(){
    dis[0]=-1;
    while (~scanf("%d",&n))
    {    
    init();
    for(int i=1;i<=n;i++){
        cin>>heap[i];
    }
    cin>>m;
    while(m--)
    {
        int x,y;
        cin>>x>>y;
        if(find(x)==find(y)){
            cout<<"-1"<<endl;
        }
        else{
            x=find(x);
            y=find(y);
            heap[x]=heap[x]/2;
            heap[y]=heap[y]/2;
            int i,j,p,q,final;
    
            i=Merge(ls[x],rs[x]);
            ls[x]=rs[x]=dis[x]=0;//将根节点断掉 
            
            j=Merge(i,x);
            fa[i]=fa[x]=j;//为了路径压缩,要将旧根和子树合并的根都指向新根 
            
            p=Merge(ls[y],rs[y]);
            ls[y]=rs[y]=dis[y]=0;
            q=Merge(p,y);
            fa[p]=fa[y]=q;
            
            final=Merge(j,q);
            fa[j]=fa[q]=final;
            cout<<heap[final]<<endl;
            //自己写的,有问题,没有将根点断掉 
           /* x=find(x);
            y=find(y);
            heap[x]=heap[x]/2;
            heap[y]=heap[y]/2;
            int i,j,p,q,final;
            fa[rs[x]]=rs[x];
            fa[ls[x]]=ls[x];
            fa[rs[y]]=rs[y];
            fa[ls[y]]=ls[y];
            
            i=Merge(ls[x],rs[x]);
            j=Merge(i,x);
            fa[i]=fa[x]=j;
            
            p=Merge(ls[y],rs[y]);
            q=Merge(p,y);
            fa[p]=fa[y]=q;
            
            final=Merge(j,q);
            fa[j]=fa[q]=final;
            cout<<heap[final]<<endl;;*/
        }
    }
        
    }
    
    return 0;
}

 

标签:rs,int,fa,MAXN,ls,heap,左偏
From: https://www.cnblogs.com/zcbiao/p/17530537.html

相关文章

  • 左偏树
    左偏树左偏树是一种可以让我们在\(O(\logn)\)的时间复杂度内进行合并的堆式数据结构。为了方便以下的左偏树为小根堆来讨论。定义外结点:左儿子或者右儿子是空节点的结点。距离:一个结点\(x\)的距离\(dis[x]\)定义为其子树中与结点\(x\)最近的外结点到\(x\)的距离......
  • 【P4331 [BalticOI 2004]】Sequence 数字序列 题解(左偏树维护动态区间中位数)
    左偏树维护动态区间中位数。传送门P4331BalticOI2004Sequence数字序列。Solution1我的思路和题解前半部分完全重合了((如果按照单调不增去分割\(a\)序列的话,对于每一段我们能很简单地得出它的最佳答案:中位数。发现严格单调很难做,很难拿捏,考虑对\(a\)序列的每一项都进......
  • 左偏树学习笔记
    一、前言左偏树是一种可以在\(O(\logn)\)内快速合并的堆式数据结构。具体来说,插入一个元素:\(O(\logn)\)。查询最值:\(O(1)\)。删除最值:\(O(\logn)\)。合并:\(O(\logn)\)。减少一个元素的值:\(O(\logn)\)。同时它可以持久化。二、定义外节点:左儿子或者右儿子为空的......
  • 洛谷P1552 [APIO2012] 派遣 题解 左偏树
    题目链接:https://www.luogu.com.cn/problem/P1552题目大意:每次求子树中薪水和不超过\(M\)的最大节点数。解题思路:使用左偏树维护一个大根堆。首先定义一个Node的结构体:structNode{ints[2],c,sz,dis;longlongsum;Node(){};Node(int_c){s......
  • 洛谷 P3377 【模板】左偏树(可并堆)题解 左偏树模板题
    题目链接:https://www.luogu.com.cn/problem/P3377维护左偏树的同时还需要维护一个并查集。但是并查集也就一个find操作。pop的时候更新f[x]的操作很神奇。示例程序:#include<bits/stdc++.h>usingnamespacestd;constintmaxn=1e5+5;intn,m,op,x,y,val[m......
  • 【理论】左偏树笔记
    左偏树是可并堆的一种实现方法。左偏,很容易形象地理解它是什么意思。但对于一棵树,如何用形象和具体化的语言来描述左偏性质?考虑定义\(dis_i\)表示\(i\)的子树中最近......
  • 左偏树(可并堆)
    左偏树(可并堆)左偏树与配对堆一样,是一种可并堆,具有堆的性质,并且可以快速合并。一种\(O(\log_2n)\)内合并的数据结构。左偏树是一棵二叉树,它不仅具有堆的性质,并且是「左......
  • 左偏树
    参考:bilibili可并堆优先队列的缺点:无法高效合并两个堆左偏树节点中的数字是它的键值,而它是个堆,因此它满足堆的性质:节点的键值小于左右子节点的键值节点外蓝色数字叫......
  • 左偏树
    一.定义与性质1.外节点:一棵二叉树中左儿子或右儿子为空的节点称为外节点。2.左偏树(LeftistTree)是一种可并堆的实现。左偏树是一棵二叉树,每个节点维护的值有:左右儿......
  • 左偏树 学习笔记
    左偏树是一类拥有下列操作的数据结构:插入一个数\(O(logn)\)求最小值\(O(1)\)删除一个节点\(O(logn)\)合并两棵树\(O(logn)\)左偏树本身具有堆的性质......