BZOJ4239 巴士走讀(最短路)

2022-05-14 14:00:05 字數 1545 閱讀 1471

點此看題面

大致題意:有\(n\)個點,且有\(m\)輛巴士,每輛巴士在第\(x_i\)時刻從\(a_i\)出發,在第\(y_i\)時刻到達\(b_i\)。多次詢問在規定到達\(n\)號點的最晚時間時,從\(1\)號點出發的最晚時間。

自己瞎想的做法,感覺非常暴力,但複雜度應該沒問題。

關鍵是很好寫,也沒怎麼除錯就過了(只是一開始智障寫\(dijkstra\)習慣性開了小根堆。。。)。

假如我們按\(y_i\)從小到大的順序列舉每一條連向\(n\)號點的邊,然後從這條邊出發在反向圖上跑最短路。

對於每個點記下到達它的最晚時間\(dis_x\),一條反向邊能走需要滿足\(dis_\ge y_i\),滿足條件即可貪心地用\(x_i\)去更新\(dis_\)。

最終\(dis_1\)就可以對所有最晚時間大於等於列舉邊\(y_i\)的詢問產生貢獻。

雖說這個做法顯然會\(t\)掉,但其正確性也是顯然的,因此只要考慮如何優化即可。

我們可以發現,顯然列舉邊的\(y_i\)越小,對答案的貢獻範圍越大。

因此,如果一條邊已經被之前的列舉邊訪問過,就無需再訪問了。

為什麼可以這麼做呢?

因為這題最短路很特殊,無論你的\(dis\)是多少,只要訪問了這條邊,都會一樣地變成\(x_i\),也就是說你用\(y_i\)更大的列舉邊去訪問這條邊,只會得到一樣的結果,而貢獻範圍顯然不如\(y_i\)較小的列舉邊。

於是,儘管我們要跑很多次\(dijkstra\),但每條邊只會經過一次,複雜度也就得到了保證。

#include#define tp template#define ts template#define reg register

#define ri reg int

#define con const

#define ci con int&

#define i inline

#define w while

#define n 100000

#define m 300000

#define pb push_back

#define mp make_pair

#define fir first

#define sec second

using namespace std;

int n,m;struct edge ;vectore[n+5];

typedef pairpr;vectorans;

class fastio

tp i void read(ty& x)

ts i void read(ty& x,ar&... y)

tp i void write(ty x)

tp i void writeln(con ty& x)

i void clear()

#undef d

}f;class dijkstra

//初始化為-1,並在答案中加入-1表示無解

i void dij(con edge& e)

BZOJ4239 巴士走讀

考慮按時刻從早到晚模擬,計算出 f i 到達i點的最晚出發時間 g i 為了趕上第i輛車的最晚出發時間 然後將所有到達n號點的巴士按到達時間排序,查詢的時候二分查詢即可。時間複雜度 o n log n include include include include define n 300010 d...

最短路樹 BZOJ 3694 最短路

題目傳送門 許可權題警告 顯然可以發現,將1到i路徑上的最後一條路切斷後,需要重新找到一條從i的子樹出發的最短路徑重新回到最短路樹上去.因此考慮一條邊什麼時候會被計算在答案中.設一條邊u v權值為val,只會可能對u,v到 lca u,v 之間的點產生影響.記錄源點1到節點i的距離為dep i 那麼...

仙人掌最短路 BZOJ 2125 最短路

題解 首先如果這是一棵樹的話,那麼我們只需要選定乙個根,之後掃一遍這棵樹,詢問的話即是兩點到根節點的距離之和減去二倍的兩點lca到根節點距離。那麼如果是一棵仙人掌的話,我們強行套用這個辦法,重新構造一棵樹。對於仙人掌中的乙個環來說,我們把該環中深度最小的點當做這個環的根,然後環上其他點連向該環,非環...