[題解][LG-P3573][POI2014]RAJ-Pally
阿新 • • 發佈:2021-12-16
設 \(f(u)\) 表示從節點 \(u\) 出發的最長路,\(g(u)\) 表示到 \(u\) 結束的最長路,這兩個 \(dp\) 的轉移都比較顯然,就不說了。那麼經過一條邊 \((u,v)\) 的最長路就是 \(g(u) + 1 + f(v)\)。
用 \(ord_u\) 表示節點 \(u\) 的拓撲序。
刪去了一個節點 \(u\) 之後,我們將節點按照拓撲序分成兩部分 \(A,B\), 其中 \(A\) 的節點的拓撲序小於 \(ord_u\) 的,\(B\) 中節點的拓撲序都是大於 \(ord_u\) 的。
那麼答案顯然只有三種情況可選:
- \(A\) 內部的,也就是 \(\max\limits_{u \in A} \{ g(u) \}\)
- \(B\) 內部的,\(\max\limits_{u \in B} \{f(u)\}\)。
- \(A\) 連向 \(B\) 的,\(\max\limits_{(u,v) \in E, u \in A, v \in B} \{g(u)+1+f(v)\}\)
現在我們可以考慮統計完刪除 \(u\) 的情況之後,將資訊更新至刪除 \(u'~(ord_{u'}=ord_{u}+1)\) 的情況。為了完成這件事,我們需要一個可刪堆(當然其他資料結構也行,但是這個程式碼短)。
起始的時候,所有節點都在 \(B\) 中,也就是將所有 \(f(u)\) 都加到堆中。接著,我們考慮按照拓撲序從小到大,刪除一個節點 \(u\)
首先是刪除 \(u\) 的資訊。刪除 \(f(u)\) , 接著刪除經過 \((v,u)~(v\in A)\) 的最長路,就可以了(霧)。
接著加回所有 \(u\) 的資訊,首先加入 \(g(u)\), 接著加入經過 \((u,v)~(v\in B)\) 的最長路。
那麼最終的程式碼如下:
#include <bits/stdc++.h> using namespace std; const int maxn = 5e5 + 5, INF = 1e9; int read_int() { int t = 0; char ch = getchar(); while (ch < '0' || ch > '9') ch = getchar(); while ('0' <= ch && ch <= '9') t = (t << 3) + (t << 1) + ch - '0', ch = getchar(); return t; } int n; struct Graph { struct Edge { int v, nex; Edge(int v = 0, int nex = 0) : v(v), nex(nex) {} } E[maxn << 1]; int hd[maxn], deg[maxn], tote; void addedge(int u, int v) { E[++tote] = Edge(v, hd[u]), hd[u] = tote, deg[v]++; } int ls[maxn], ls_sz, f[maxn]; queue<int> q; void topo() { for (int i = 1; i <= n; i++) if (!deg[i]) q.push(i); while (!q.empty()) { int u = q.front(); q.pop(), ls[++ls_sz] = u; for (int i = hd[u]; i; i = E[i].nex) { int v = E[i].v; deg[v]--; if (!deg[v]) q.push(v); } } for (int p = n; p >= 1; p--) { int u = ls[p]; for (int i = hd[u]; i; i = E[i].nex) f[u] = max(f[u], f[E[i].v] + 1); } } } G, rG; struct RbHeap { priority_queue<int> q, del_q; void push(int val) { q.push(val); } void pop(int val) { del_q.push(val); } int top() { while (del_q.size() && q.top() == del_q.top()) q.pop(), del_q.pop(); return (q.size() ? q.top() : -INF); } } hp; int main() { int m; n = read_int(), m = read_int(); for (int i = 1; i <= m; i++) { int u = read_int(), v = read_int(); G.addedge(u, v), rG.addedge(v, u); } G.topo(), rG.topo(); int ans1, ans2; for (int i = 1; i <= n; i++) hp.push(G.f[i]); ans2 = hp.top(); for (int p = 1; p <= n; p++) { int u = G.ls[p]; hp.pop(G.f[u]); for (int i = rG.hd[u]; i; i = rG.E[i].nex) { int v = rG.E[i].v; hp.pop(rG.f[v] + 1 + G.f[u]); } int val = hp.top(); if (val < ans2) ans1 = u, ans2 = val; hp.push(rG.f[u]); for (int i = G.hd[u]; i; i = G.E[i].nex) { int v = G.E[i].v; hp.push(rG.f[u] + 1 + G.f[v]); } } printf("%d %d\n", ans1, ans2); return 0; }