Codeforces 980F Cactus to Tree - 动态规划 - 单调队列

题目传送门

  通往未知网站的火车站

  通往不明网站的火车站

  通完??网站的火车站

题目大意

   给定一个$n$个点$m$条边的仙人球。要求求出使它变为树后,距离每个点最远的点的距离最小可能为多少。

  实质上是求出以每个点为根的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 }

猜你喜欢

转载自www.cnblogs.com/yyf0309/p/9265566.html