關於配對堆的一些小姿勢:
1、配對堆是一顆多叉樹。
2、包含優先隊列的所有功能,可用於優化Dijkstra算法。
3、屬於可並堆,因此對於集合合並維護最值的問題很實用。
4、速度快於一般的堆結構(左偏樹,斜堆,隨機堆……),具體時間復雜度:
- 合並(Merge):$O(1)$;
- 插入(Insert/Push):$O(1)$;
- 修改值(Change):$O(1) \sim O(\log n)$;
- 取出維護的最值(Top):$O(1)$;
- 彈出堆頂元素(Pop):$O(\log n)$;
我們依然拿洛谷的P4779 【模板】單源最短路徑(標准版)來驗證代碼的正確性。
以下是配對堆優化Dijkstra算法的AC代碼:
#include<bits/stdc++.h> #include<ext/pb_ds/priority_queue.hpp> using namespace std; using namespace __gnu_pbds; typedef pair<int,int> pii; typedef __gnu_pbds::priority_queue<pii,greater<pii>,pairing_heap_tag> Heap; const int maxn=1e5+10; const int INF=0x3f3f3f3f; int n,m,s; struct Edge{ int u,v,w; Edge(int _u=0,int _v=0,int _w=0){u=_u,v=_v,w=_w;} }; vector<Edge> E; vector<int> G[maxn]; void addedge(int u,int v,int w) { E.push_back(Edge(u,v,w)); G[u].push_back(E.size()-1); } int d[maxn]; void dijkstra() { memset(d,0x3f,sizeof(d)); Heap Q; Heap::point_iterator id[maxn]; d[s]=0; id[s]=Q.push(make_pair(d[s],s)); while(!Q.empty()) { int u=Q.top().second; Q.pop(); for(int i=0;i<G[u].size();i++) { Edge &e=E[G[u][i]]; int v=e.v; if(d[v]>d[u]+e.w) { d[v]=d[u]+e.w; if(id[v]!=0) Q.modify(id[v],make_pair(d[v],v)); else id[v]=Q.push(make_pair(d[v],v)); } } } } int main() { scanf("%d%d%d",&n,&m,&s); for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); addedge(u,v,w); } dijkstra(); for(int i=1;i<=n;i++) printf("%d%s",d[i],((i==n)?"\n":" ")); }