【模板】左偏树

左偏树是可合并堆的一种实现方式,可合并堆还有其他实现方式比如斜堆,然而我这种蒟蒻只会写左偏树。

模板里的左偏树为大根堆,支持合并,查询堆顶和弹出堆顶操作,对于已经删除的位置,查询将返回-1,为了确保弹出的正常进行,模板里使用的并查集没有使用路径压缩,因此常数可能会比较大。

 1 #include<stdio.h>
 2 #define maxn 1000
 3 struct node{int ch[2],w,dist;};
 4 int n,op,ori[maxn];
 5 void swp(int &x,int &y){x^=y;y^=x;x^=y;}
 6 struct ltt
 7 {
 8     node lt[maxn];
 9     int fa[maxn]; bool sta[maxn];
10     //int fi(int p){if(fa[p]!=p){fa[p]=fi(fa[p]);}return fa[p];}
11     int fi(int p){return fa[p]==p?p:fi(fa[p]);}
12     void ini()
13     {for(int i=1;i<=n;i++) fa[i] = i,lt[i].w = ori[i];}
14     int merge(int p,int q)
15     {
16         if(!p||!q) return !p ? q : p;
17         if(lt[p].w<lt[q].w) swp(p,q);
18         lt[p].ch[1] = merge(q,lt[p].ch[1]);
19         if(!lt[p].ch[0]||lt[lt[p].ch[0]].dist<lt[lt[p].ch[1]].dist) swp(lt[p].ch[0],lt[p].ch[1]);
20         lt[p].dist = !lt[p].ch[1] ? 0 : lt[lt[p].ch[1]].dist + 1;
21         return p;
22     }
23     void mer(int p,int q)//合并p位置和q位置所在的左偏树
24     {
25         if(sta[p]||sta[q]||fi(p)==fi(q)) return;
26         fa[fi(p)]=fa[fi(q)]=merge(fi(p),fi(q));
27     }
28     int top(int p)//返回p位置所在堆的堆顶,如果p位置已经被删除,返回-1
29     {
30         int r = fi(p); if(sta[r]) return -1;
31         return lt[r].w;
32     }
33     int exmax(int p)//弹出p位置所在堆的堆顶,如果p位置已被删除,返回-1
34     {
35         int r = fi(p); if(sta[r]) return -1;
36         sta[r] = true;
37         int lc = lt[r].ch[0],rc = lt[r].ch[1];
38         fa[lc] = fa[rc] = merge(lc,rc);
39         return lt[r].w;
40     }
41 }T;
42 int main()
43 {
44     scanf("%d%d",&n,&op);
45     int i,p,q,flag;
46     for(i=1;i<=n;i++) scanf("%d",ori+i);
47     T.ini();
48     for(i=1;i<=op;i++)
49     {
50         scanf("%d",&flag);
51         if(flag==1)
52         {scanf("%d%d",&p,&q);T.mer(p,q);}
53         else if(flag==2){scanf("%d",&p);printf("%d\n",T.exmax(p));}
54         else{scanf("%d",&p);printf("%d\n",T.top(p));}
55     }
56     return 0;
57 }

时间: 2024-12-15 09:44:12

【模板】左偏树的相关文章

模板 - 左偏树 + 并查集

这两个经常混在一起用的样子,封成同一个好了. #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=

模板:左偏树

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

luogu 【P3377】 【模板】左偏树

左偏树模板... #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <algorithm> #include <cctype> #include <iostream> #define For(i, l, r) for(int i = (l); i <= (int)(r); ++i) #define For

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

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

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

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

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

左偏树的树高是 $log(n)$ 级别的,所以在查询祖先的时候是不可以直接顺着左偏树上的父亲查询的. 另开一个并查集,在并查集上进行路径压缩的查询即可. Code: #include <cstdio> #include <algorithm> #include <cstring> #define maxn 100006 #define setIO(s) freopen(s".in","r",stdin) using namespa

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

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