今年暑假外校集訓的時候一道題標算是最短路擴展,然而std用的是pbds,於是就產生了研究的興趣。結果那個標程我現在死都找不到了233
定義:
在知乎上看到有oier去年向CCF發了郵件,得到的回復是pbds庫可以用,但是不能寫這句話:
using namespace __gnu_pbds;
存圖為證。
--------------------------------------------------------------------------原答案分割線--------------------------------------------------------------------------------------------------------------------------------------
pbds是一個封裝了眾多高效又實用(相對於STL)的數據結構的庫,包括堆,平衡樹,哈希表等。然而目前仍然不清楚NOIP中能否使用。在CCF2011年發布的關於NOI系列賽編程語言使用限制的規定中明確規定C/C++程序禁止使用內嵌匯編和以下划線開頭的庫函數或宏(自己定義的除外),然而在WC2015營員交流中一位同學卻說pbds在NOI系列賽事中可以使用,這就造成了現在的這種尷尬境地。
由於本人實在蒟蒻,加上pbds的平衡樹在維護有序序列時對存在重復元素的情況維護難度較大,且該問題用STL中的vector就可以妥善解決,(之前自己智障),在此只介紹pbds中堆的用法。
用法:
由於bits/stdc++.h不覆蓋pbds,使用時需加上#include<ext/pb_ds/priority_queue.hpp>和using namespace __gnu_pbds;(gnu前兩條下划線)。(命名空間不能使用)
注意:pbds的堆在定義時不需要vector<int>。
定義一個int類型的小根堆:__gnu_pbds::priority_queue<int,greater<int>,TAG>pq;
TAG指明了所用堆的類型,共有以下幾種:
pairing_heap_tag:配對堆
thin_heap_tag:斐波那契堆
binomial_heap_tag:二項堆
binary_heap_tag:二叉堆
如果是大根堆的話只需要去掉greater<int>即可,也可以定義結構體類型或者其他類型,只要重載了<運算符就可以使用。
這些堆普遍支持push,pop,top和join操作。最后一個操作是將兩個堆合並,使用方法:a.join(b);//將堆b合並至堆a中
配對堆和斐波那契堆的理論復雜度均十分優異,push,top,join都能做到均攤O(1),pop能做到O(logn)。
二項堆的各種操作復雜度都是O(logn)。二叉堆的復雜度不知,但實際運行速度極慢,反而不如std和手寫堆,不知是何原因,不建議使用。
拿一道最短路例題來測試一下各種堆的速度吧:
例題:
Luogu P3371 【模板】單源最短路徑 題目鏈接
題意:給定一張n個點,m條邊的有向圖和起點s,要求輸出s到每個點的最短距離,若不可達輸出2147483647。
數據范圍:n<=10000,m<=500000。
題解:SPFA或dijkstra堆優化。
配對堆:756ms
斐波那契堆:664ms
二項堆:812ms
二叉堆:1516ms+3TLE
TAG留空(我也不知道這是什么騷操作):586ms
基本符合理論復雜度。在平時或者考場上時建議使用配對堆或斐波那契堆或者直接留空。