meaning of the title
Sol
The most intuitive idea is to find the longest way after deleting each point. Let's consider how to find this thing
Set \ (f[i] \) to represent the longest path length ending with \ (I \), and \ (g[i] \) to represent the longest path length starting with \ (I \)
According to the nature of DAG, it is obvious that when we delete a point, the whole set will be divided into two parts: the topological order is less than / greater than the current point
Then the longest path at this time can be obtained by calculating \ (f(u) + f(v) +1 \) of the edge \ ((u, v) \) connecting two sets
In this way, we can directly maintain the edge set. When we count the answers of each point, we first delete the contribution statistical answers of the input edge, and then add the contribution of the output edge
Obviously, the line tree can be maintained, in fact, the heap can also be maintained. See the code for details (copied from yyb big guy)
#include<bits/stdc++.h> #define chmax(x, y) (x = (x > y ? x : y)) #define chmin(x, y) (x = (x < y ? x : y)) using namespace std; const int MAXN = 1e6 + 10, INF = 1e9 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int N, M, a1 = INF, a2; class MyPriorityQueue { public: priority_queue<int> q1, q2; void push(int x) { q1.push(x); } int pop(int x) { q2.push(x); } bool empty() { while(!q2.empty() && (q1.top() == q2.top())) q1.pop(), q2.pop(); return q1.size() == 0; } int top() { return empty() ? INF : q1.top(); } }; MyPriorityQueue Q; struct Graph { vector<int> v[MAXN]; int f[MAXN], inder[MAXN], id[MAXN], tot; Graph() { tot = 0; } void AddEdge(int x, int y) { v[x].push_back(y); inder[y]++; } void Topsort() { queue<int> q; for(int i = 1; i <= N; i++) if(!inder[i]) q.push(i); while(!q.empty()) { int p = q.front(); q.pop(); id[++tot] = p; for(int i = 0; i < v[p].size(); i++) { int to = v[p][i]; chmax(f[to], f[p] + 1); if(!(--inder[to])) q.push(to); } } } }; Graph Gs, Gt; int main() { N = read(); M = read(); for(int i = 1; i <= M; i++) { int x = read(), y = read(); Gs.AddEdge(x, y); Gt.AddEdge(y, x); } Gs.Topsort(); Gt.Topsort(); for(int i = 1; i <= N; i++) Q.push(Gt.f[i]); for(int t = 1; t <= N; t++) { int x = Gs.id[t]; Q.pop(Gt.f[x]); for(int i = 0; i < Gt.v[x].size(); i++) { int to = Gt.v[x][i]; Q.pop(Gs.f[to] + Gt.f[x] + 1); } int now = Q.top(); Q.push(Gs.f[x]); if(now < a1) a1 = now, a2 = x; for(int i = 0; i < Gs.v[x].size(); i++) { int to = Gs.v[x][i]; Q.push(Gs.f[x] + Gt.f[to] + 1); } } printf("%d %d\n", a2, a1); return 0; }