點此看題面
大致題意:有\(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到根節點距離。那麼如果是一棵仙人掌的話,我們強行套用這個辦法,重新構造一棵樹。對於仙人掌中的乙個環來說,我們把該環中深度最小的點當做這個環的根,然後環上其他點連向該環,非環...