支援刪除,合併,查詢最大或最小值(還可以查詢中位數哦)
單次時間複雜度\(o(log n)\)
由最後乙個性質 保證一次到堆底的時間複雜度為\(log\)級
只需要學會\(merge\) 其她就很簡單了
\(merge\)就是將兩個堆合併
inline int merge(int u,int v)
好了其實現在你已經可以\(a\)
這道題了
刪除乙個節點 等價於 合併這個節點的左右子樹
每一顆左偏樹 只能維護最大最小值中的乙個
由性質1得 堆的最大最小值為根的權值
第x個數和第y個數所在的小根堆合併
這句活用並查集實現
注意要路徑壓縮
板子題
#include #include #define reg register int
using namespace std;
const int maxn = 100005;
int n,m;
namespace leftist_tree
; node heap[maxn];
bool exist[maxn];
int dis[maxn],rt[maxn];
inline void init()
inline int merge(int u,int v)
inline int find_set(int x) }
using namespace leftist_tree;
int main()
else
x = find_set(x);
printf("%d\n",heap[x].val);
exist[x] = 1;
rt[heap[x].l] = rt[heap[x].r] = rt[x] = merge(heap[x].l,heap[x].r);
heap[x].l = heap[x].r = dis[x] = 0;
} }return 0;
}
提公升一下:
分成多個不下降的子串行,求出每個子串行的中位數
對於連續上公升的子串行的中位數
我們把她合併為乙個堆 再求中位數
乙個堆的中位數等於根的權值的充要條件就是
這個堆只有我們要求得堆的大小的一半(此時此堆仍是大(小)根堆)
稍微想一下應該就可以理解了吧qaq
#include #include #include using namespace std;
#define reg register int
const int maxn = 1e6 + 10;
typedef long long ll;
int n,num[maxn],son[maxn][2];
templateinline t read(t x)
while(isdigit(a))
return x * f;
}namespace leftist_tree ;
node heap[maxn];
int dis[maxn];
inline int merge(int u,int v)
}using namespace leftist_tree;
inline void init()
}int cnt,b[maxn];
ll ans;
inline void solve() ;
while(cnt > 1&&heap[cnt - 1].val > heap[cnt].val)
只保留一半元素
heap[cnt].val = num[heap[cnt].rt];
} }for(reg i = 1; i <= cnt; i++)
for(reg j = heap[i].lef; j <= heap[i].rig; j++)
printf("%lld\n",ans);
}int main()
左偏樹學習筆記
左偏樹是一種基於二叉樹的可並堆。定義乙個節點的 距離 dis xdis x disx 為它到空節點的最短路長度,左偏樹強制要求 dis lson dis rson dis ge dis dislso n d isrs on 所以 dis x di srso n 1dis x dis 1 disx d...
左偏樹 學習筆記
首先要知道左偏樹是用來幹什麼的。如果給我們兩個優先序列,然後讓我把這兩個優先佇列合併成乙個優先佇列。如果直接用堆,就是將乙個佇列裡面的數不斷彈出然後扔到另乙個佇列裡。複雜度是 o n n為佇列中數的個數。但是用左偏樹就可以做到 log n 1 n 2 ps 為了便於討論,本文所有的左偏樹均已小根樹為...
學習筆記 左偏樹
左偏樹是一種可並堆,除了堆的基本功能,最大的特點就是支援合併堆,甚至比普通堆好寫。下面敘述以小根堆為例,大根堆對稱。o log n 求乙個數所在堆的根 o 1 求最小值 o log n 合併兩個堆 o log n 刪除最小值 o log n 插入乙個數 n 是插入的總節點數 或當前堆的節點數 str...