【10.27校内测试】【可删堆+拓排】
Solution
有向图要找最长路径的话,可以想到拓扑序转移。正反跑两边处理出每个点离起点和终点的最大值。访问每条边就能统计出经过每条边最长路径的长度。
问题是怎么统计出删除每个点的影响?
拓扑排序后,可以发现,删除层数靠后的点会对前面产生影响,因为此时想统计前面的边存在的最长路就不能判掉经过这个点的路径,所以只能按拓扑序从前往后删点。
这里直接说做法吧,维护一个大根堆,储存当前枚举到的最长路径,首先把每个点离终点的最大值推入堆中。每枚举删除一个点,就把它对前面点有影响的路径删掉,更新答案后再把它对后面的路径加入堆中,做完所有点即可。
但是堆不能直接实现制定元素删除操作,所以要用可删堆QAQ
其实就是两个堆,一个维护当前堆,一个维护待删除的元素,每次删除就往第二个堆中加入元素,实际操作是在取出过程中实现的,如果当前两个堆顶元素相同时,就删除两个堆顶即可。
%%%$jzy$大佬码风新奇,我等一般人只能仰望%%%
Code
#include<bits/stdc++.h> #define RG register using namespace std; inline char nc() { static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline void read(int &x) { x = 0; int t = 1; char ch = nc(); while(ch > '9' || ch < '0') { if(ch == '-') t = -1; ch = nc(); } while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = nc(); } x *= t; } struct Node { int v, nex; } Edge[500005], Edge_rz[500005]; int stot_rz = 0, h_rz[100005], stot, h[100005]; void add(int u, int v) { Edge[++stot] = (Node) {v, h[u]}; h[u] = stot; Edge_rz[++stot_rz] = (Node) {u, h_rz[v]}; h_rz[v] = stot_rz; } class Heap { private: priority_queue < int > q1; priority_queue < int > q2; public: inline void init() { while(!q1.empty()) q1.pop(); while(!q2.empty()) q2.pop(); } inline void push(int x) { q1.push(x); } inline void del(int x) { q2.push(x); } inline int top() { while(!q2.empty() && q1.top() == q2.top()) { q1.pop(); q2.pop(); } return q1.top(); } } Q; int in[100005], q[100005], st[100005], ed[100005], ans, id, n, m; int main() { freopen("johnny.in", "r", stdin); freopen("johnny.out", "w", stdout); int T; read(T); while(T --) { memset(h, 0, sizeof(h)); memset(h_rz, 0, sizeof(h_rz)); stot = 0, stot_rz = 0; int t = 0, hi = 1; memset(q, 0, sizeof(q)); memset(in, 0, sizeof(in)); memset(st, 0, sizeof(st)); memset(ed, 0, sizeof(ed)); ans = 0x3f3f3f3f, id = 0; Q.init(); read(n); read(m); while(m --) { int u, v; read(u); read(v); add(u, v); in[v] ++; } for(int i = 1; i <= n; i ++) if(!in[i]) q[++t] = i; while(hi <= t) { int u = q[hi ++]; for(RG int i = h[u]; i; i = Edge[i].nex) { int v = Edge[i].v; if((-- in[v]) == 0) q[++t] = v; } } for(RG int i = 1; i <= n; i ++) { int u = q[i]; for(RG int j = h[u]; j; j = Edge[j].nex) { int v = Edge[j].v; st[v] = max(st[v], st[u] + 1); } } for(RG int i = n; i >= 1; i --) { int u = q[i]; for(RG int j = h_rz[u]; j; j = Edge_rz[j].nex) { int v = Edge_rz[j].v; ed[v] = max(ed[v], ed[u] + 1); } } for(int i = 1; i <= n; i ++) Q.push(ed[i]); for(RG int i = 1; i <= n; i ++) { int u = q[i]; for(int j = h_rz[u]; j; j = Edge_rz[j].nex) { int v = Edge_rz[j].v; Q.del(st[v] + ed[u] + 1); } Q.del(ed[u]); int now = Q.top(); if(now < ans) ans = now, id = u; else if(now == ans) id = min(id, u); for(RG int i = h[u]; i; i = Edge[i].nex) { int v = Edge[i].v; Q.push(st[u] + ed[v] + 1); } Q.push(st[u]); } printf("%d %d\n", id, ans); } return 0; }