实质上是求出以每个点为根的bfs生成树的深度。
显然,当以点$i$为根的bfs生成树时,不经过包含点$i$所在环的环边的子树和以$1$为根的bfs生成树中的同样的点组成的图是一样(因为,当以1为根时,bfs访问到点i,后续过程一样)。
因此,考虑用$L[i]$表示不经过点$i$所在环的环边的从$i$出发,在以1为根的bfs生成树的$i$的子树中结束的最长路。这个可以从$1$开始进行1次bfs求出、
然后考虑环上,首先从"根"开始处理。假如通过某种方式已经出来出从$i$号点经过它的父节点但不经过它所在的环的环边的最长路。
这样相当于求出环上的每个点不经过它们所在的环的环边的最长路。然后现在考虑加上环边。
对于每个点$i$,我们希望最大化$dist(i, j) + L[j]$。前一部分可以拆成一个差,然后在环上分顺逆时针转着更新答案。
然而有个问题,必须要保证在环上的路径最短。但是我们知道简单环上两点之间最短路径也是很容易找到的,如果环的大小为$k$,那么距离不超过$\left \lfloor k / 2 \right \rfloor$的那条路径一定是这两点间的最短路。因此,还需要用一个优先队列来维护,如果队首距离当前枚举的点的距离超过了环大小的一半就把它弹掉。这个问题因为一个决策不优,那么它就一定不会成为最优决策,因此可以只用维护一个单调队列。
然后怎么计算下传的信息,首先是经过环边的最长路,然后再在它的子树中除去当前枚举的边,挑一个深度最深的深度选最大值。对于环顶还需要考虑经过它的父节点的最长路也要下传信息。
附上开小数组的惨痛教训(还是new大法好),真·一堆鬼畜的事情。另外很想吐槽一下cf怎么突然吃掉assert的诊断信息。
Code
1 /** 2 * Codeforces 3 * Problem#980F 4 * Accepted 5 * Time: 857ms 6 * Memory: 76052k 7 */ 8 #include <algorithm> 9 #include <iostream> 10 #include <cassert> 11 #include <cstdlib> 12 #include <cstring> 13 #include <cstdio> 14 #include <vector> 15 #include <queue> 16 using namespace std; 17 typedef bool boolean; 18 19 #define pii pair<int, int> 20 #define fi first 21 #define sc second 22 23 const int N = 5e5 + 5; 24 25 int n, m; 26 vector< pii > *g; 27 vector< vector<int> > cir; 28 int cis[N], maxl[N], L[N], Z[N]; 29 boolean vis[N], ib[N << 1]; // is it a bridge 30 31 inline void init() { 32 scanf("%d%d", &n, &m); 33 g = new vector<pii>[(n + 1)]; 34 for (int i = 1, u, v; i <= m; i++) { 35 scanf("%d%d", &u, &v); 36 g[u].push_back(pii(v, i)); 37 g[v].push_back(pii(u, i)); 38 } 39 } 40 41 int ts = 0; 42 int dfn[N], low[N]; 43 void tarjan(int p, int fa) { 44 dfn[p] = low[p] = ++ts; 45 for (auto e : g[p]) { 46 if (e.fi == fa) continue; 47 if (!dfn[e.fi]) { 48 tarjan(e.fi, p); 49 low[p] = min(low[p], low[e.fi]); 50 if (low[e.fi] == dfn[e.fi]) 51 ib[e.sc] = true; 52 } else 53 low[p] = min(low[p], dfn[e.fi]); 54 } 55 } 56 57 void dfs(int p) { 58 vis[p] = true; 59 cir.back().push_back(p); 60 cis[p] = (signed) cir.size() - 1; 61 for (auto e : g[p]) 62 if (!vis[e.fi] && !ib[e.sc]) 63 dfs(e.fi); 64 } 65 66 queue<int> que; 67 void bfs(int s) { 68 int tp = 0; 69 int *tr = new int[(n + 1)]; 70 int *par = new int[(n + 1)]; 71 que.push(s); 72 memset(vis, false, sizeof(vis)); 73 tr[++tp] = s, par[s] = 0, vis[s] = true; 74 while (!que.empty()) { 75 int e = que.front(); 76 que.pop(); 77 for (auto eu : g[e]) { 78 if (vis[eu.fi]) continue; 79 vis[eu.fi] = true; 80 tr[++tp] = eu.fi, par[eu.fi] = e; 81 assert(eu.fi != s); 82 que.push(eu.fi); 83 } 84 } 85 86 for (int i = n; i > 1; i--) { 87 int p = tr[i]; 88 for (auto e : g[p]) { 89 if (e.fi == par[p]) { 90 maxl[e.fi] = max(maxl[e.fi], maxl[p] + 1); 91 if (ib[e.sc]) 92 L[e.fi] = max(L[e.fi], maxl[p] + 1); 93 break; 94 } 95 } 96 } 97 delete[] tr; 98 delete[] par; 99 } 100 101 int ql, qr; 102 pii ar[N << 1]; 103 void deal(int p, int fa, int upval) { 104 L[p] = max(L[p], upval); 105 vector<int> &circ = cir[cis[p]]; 106 int k = (signed) circ.size(), lim = k >> 1; 107 for (int it = 0; it < 2; it++) { 108 ql = 1, qr = 0; 109 for (int i = 0, e; i < 2 * k; i++) { 110 e = circ[i % k]; 111 while (ql <= qr && i - ar[ql].sc > lim) 112 ql++; 113 if (ql <= qr) 114 Z[e] = max(Z[e], i + ar[ql].fi); 115 while (ql <= qr && ar[qr].fi <= L[e] - i) 116 qr--; 117 ar[++qr] = pii(L[e] - i, i); 118 } 119 reverse(circ.begin(), circ.end()); 120 } 121 122 for (auto u : circ) { 123 int fiv = 0, scv = 0; 124 for (auto e : g[u]) 125 if (e.fi != fa && ib[e.sc]) { 126 if (maxl[e.fi] + 1 > fiv) 127 scv = maxl[e.fi] + 1, swap(scv, fiv); 128 else if (maxl[e.fi] + 1 > scv) 129 scv = maxl[e.fi] + 1; 130 } 131 132 for (auto e : g[u]) 133 if (e.fi != fa && ib[e.sc]) { 134 int pv = max(Z[u], upval), val = maxl[e.fi] + 1; 135 if (val == fiv) 136 pv = max(pv, scv); 137 else 138 pv = max(pv, fiv); 139 deal(e.fi, u, pv + 1); 140 } 141 } 142 } 143 144 inline void solve() { 145 tarjan(1, 0); 146 for (int i = 1; i <= n; i++) 147 if (!vis[i]) { 148 cir.push_back(vector<int>()); 149 dfs(i); 150 } 151 bfs(1); 152 deal(1, 0, 0); 153 for (int i = 1; i <= n; i++) 154 printf("%d ", max(L[i], Z[i])); 155 } 156 157 int main() { 158 init(); 159 solve(); 160 return 0; 161 }