【模板】左偏树(可并堆) 可并堆_并查集

左偏树的树高是 $log(n)$ 级别的,所以在查询祖先的时候是不可以直接顺着左偏树上的父亲查询的.

另开一个并查集,在并查集上进行路径压缩的查询即可.

Code:

#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 100006
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int n,m;
struct MHEAP{
    int f[maxn],ch[maxn][2],val[maxn],dis[maxn];
    int merge(int x,int y){
        if(!x||!y) return x+y;
        if(val[x]>val[y]||(val[x]==val[y]&&y<x)) swap(x,y);
        ch[x][1]=merge(ch[x][1],y);
        f[ch[x][1]]=f[ch[x][0]]=x;
        if(dis[ch[x][0]]<dis[ch[x][1]]) swap(ch[x][1],ch[x][0]);
        dis[x]=dis[ch[x][1]]+1;
        return x;
    }
    int getfa(int x)
    {
        return f[x]!=x ? f[x]=getfa(f[x]) : x;
    }
    void pop(int x)
    {
        f[ch[x][0]]=ch[x][0],f[ch[x][1]]=ch[x][1];
        f[x]=merge(ch[x][0],ch[x][1]);
        val[x]=-1;
    }
    void opt1(int x,int y)
    {
        if(val[x]==-1||val[y]==-1) return;
        if(x==y) return ;
        int a=getfa(x),b=getfa(y);
        if(a==b) return ;
        merge(a,b);
    }
    void opt2(int x)
    {
        if(val[x]==-1)
        {
            printf("-1\n");
            return;
        }
        int a=getfa(x);
        printf("%d\n",val[a]);
        pop(a);
    }
}T;
int main(){
    //setIO("input");
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i) scanf("%d",&T.val[i]);
    for(int i=1;i<=n;++i) T.f[i]=i;
    for(int i=1,opt,a,b;i<=m;++i){
        scanf("%d",&opt);
        if(opt==1) scanf("%d%d",&a,&b),T.opt1(a,b);
        if(opt==2) scanf("%d",&a),T.opt2(a);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/10353766.html

时间: 2024-12-07 12:20:54

【模板】左偏树(可并堆) 可并堆_并查集的相关文章

模板 - 左偏树 + 并查集

这两个经常混在一起用的样子,封成同一个好了. #include<bits/stdc++.h> using namespace std; typedef long long ll; int solve(); int main() { #ifdef Yinku freopen("Yinku.in","r",stdin); #endif // Yinku solve(); } int n,m; const int MAXN=100005; int tot,v[

算法模板——左偏树(可并堆)

实现的功能——输入1 x,将x加入小根堆中:输入2,输出最小值并去在堆中除掉 1 var 2 i,j,k,l,m,n,head:longint; 3 a,lef,rig,fix:array[0..100000] of longint; 4 function min(x,y:longint):longint;inline; 5 begin 6 if x<y then min:=x else min:=y; 7 end; 8 function max(x,y:longint):longint;inl

[模板]左偏树

可并堆 可以支持合并的堆. /*大根堆*/ struct heap{ int l,r,w; }h[N]; int rt[N];//第i个堆的根的下标 /*合并以x,y为根的堆*/ inline int merge(int x,int y){ int t; //其中一个堆为空 if(!x||!y) return x+y; //使得x,y两个根中x大 if(h[x].w<h[y].w){ int t=x;x=y;y=t; } //保持堆两边的平衡 h[x].r=merge(y,h[x].r); t=

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

因为也是昨天刚接触左偏树,从头理解,如有不慎之处,跪请指教. 左偏树: 什 么是(fzy说)左偏树啊? 前置知识: 左偏树中dist:表示到右叶点(就是一直往右下找,最后一个)的距离,特别的,无右节点的为0. 堆:左偏树是个堆. 关于左偏性质:可以帮助堆合并(研究深了我也不懂的,看代码理解) 对于任意的节点,dist[leftson]>=dist[rightson],体现了左偏性质. 同理可得:对于任意右儿子的父亲节点的dist自然等于右儿子的dist+1喽 关于各种操作: merge: 是插入

模板:左偏树

如果你知道priority_queue的话,那自然就知道左偏树的目的了. 左偏树的目的和优先队列一致,就是求出当前所在堆中的最大(小)值. 但是我们作为高贵的C++选手,我们为什么还要学习左偏树呢. 当然是因为priority_queue太!慢!了! ———————————————————————————————————— 概念引入: 对于左偏树,我们引入两个概念: 外节点:如果该节点的左子树或右子树为空,那么该节点为外节点. 距离(dis):该节点到达最近的外节点经过的边的个数. 我们同时将优

浅析左偏树的性质及其应用

本文是看了黄源河的论文后才写的 如果本人有哪些地方写得不对的,希望各位大佬改正ORZ 学习C++的大佬应该都会优先队列(原谅我的菜,我连priority_queue都不会拼) 左偏树说到底就是一个升级版的堆 因为左偏树拥有所有堆拥有的功能比如说插入一个节点,取出堆顶和删除堆顶 我们的左偏树的优秀到底体现在哪呢? 左偏树可以合并两个堆!!! 如果我们用普通的做法合并两个堆是需要O(N)的时间 那么如果合并操作非常多 那么堆就不在实用了 先来规定左偏树的一些概念 外节点:一个没有右儿子的节点成为外节

[BZOJ1455] 罗马游戏|左偏树

1455: 罗马游戏 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 870  Solved: 347[Submit][Status][Discuss] Description 罗马皇帝很喜欢玩杀人游戏. 他的军队里面有n个人,每个人都是一个独立的团.最近举行了一次平面几何测试,每个人都得到了一个分数. 皇帝很喜欢平面几何,他对那些得分很低的人嗤之以鼻.他决定玩这样一个游戏. 它可以发两种命令: 1. Merger(i, j).把i所在的团和j所在的团

【转】左偏树(可合并优先队列)

[可并堆与左偏树] 我们最常用的二叉堆,是最常用的优先队列,它可以在O(logN)内实现插入和删除最小值操作.但是对于合并两个有序的优先队列,二叉堆就显得力不从心了. 左偏树是一种可并堆(Mergeable Heap),意思是可以在O(logN)时间内完成两个堆的合并操作.左偏树(Leftist Tree),或者叫左倾树,左式树,左式堆(Leftist Heap),左堆.顾名思义,它好象是向左偏的,实际上它是一种趋于非常不平衡的二叉树结构,但却能够实现对数级的合并时间复杂度. [左偏树的定义]

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

P3377 [模板]左偏树(可并堆) 题目描述 如题,一开始有N个小根堆,每个堆包含且仅包含一个数.接下来需要支持两种操作: 操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作) 操作2: 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作) 输入输出格式 输入格式: 第一行包含两个正整数N.M,分别表示一开始小根堆的个数和接下来操作的个数. 第二行包含N个正整数,其中第i个