Codeforces 835F Roads in the Kingdom - 动态规划
路径可以分为两部分:跨过环 和 在树内部。
要删除一条边,使图形变为一棵树,那么只能删去环上的一条边,因此,我们无法改变第二部分的路径,但是可以改变第一部分。
对于第二部分可以通过两次搜索或者树形动态规划解决。
对于第一部分,考虑枚举删去环上的一条边。但是发现仍然不太方便处理,因为不好维护环上的信息。仍然考虑剖环成链。
假设环的大小为$k$,从剖点开始依次将所有点标号1到$k$。
当一条边被删除后,第二部分可能成为答案的情况有两种:
- 不跨过剖点和被删边的路径
- 跨过剖点但不经过被删边的路径
因此考虑维护一些数组。
- 在$1, 2, \cdots, i$及其所在的树中的最长路。
- 从$1$开始,到$1, 2, \cdots, i$及其所在的树中的最长路。
- 在$k, k - 1, \cdots, i$及其所在的树中的最长路。
- 从$k$开始,到$k, k - 1, \cdots, i$及其所在的树中的最长路。
这四个部分都可以线性预处理出来。然后枚举删掉的环边就能统计第一部分的答案。
Code
1 /** 2 * Codeforces 3 * Problem#835F 4 * Accepted 5 * Time: 155ms 6 * Memory: 27100k 7 */ 8 #include <bits/stdc++.h> 9 #ifndef WIN32 10 #define Auto "%lld" 11 #else 12 #define Auto "%I64d" 13 #endif 14 using namespace std; 15 typedef bool boolean; 16 17 typedef class Edge { 18 public: 19 int ed, nx, w; 20 21 Edge(int ed = 0, int nx = 0, int w = 0):ed(ed), nx(nx), w(w) { } 22 }Edge; 23 24 typedef class MapManager { 25 public: 26 int ce; 27 int* h; 28 Edge* es; 29 30 MapManager() { } 31 MapManager(int n, int m):ce(-1) { 32 h = new int[(n + 1)]; 33 es = new Edge[(m + 1)]; 34 memset(h, -1, sizeof(int) * (n + 1)); 35 } 36 37 void addEdge(int u, int v, int w) { 38 es[++ce] = Edge(v, h[u], w); 39 h[u] = ce; 40 } 41 42 Edge& operator [] (int pos) { 43 return es[pos]; 44 } 45 }MapManager; 46 47 #define ll long long 48 49 const signed ll llf = (signed ll) ((~0ull) >> 1); 50 51 int n; 52 int ccir, cc; 53 MapManager g; 54 stack<int> s; 55 boolean *vis, *icir; 56 int *cir, *nw; 57 ll *ap[2], *cp[2], *dep, *dis; 58 59 inline void init() { 60 scanf("%d", &n); 61 vis = new boolean[(n + 1)]; 62 icir = new boolean[(n + 1)]; 63 cir = new int[(n + 1)]; 64 nw = new int[(n + 1)]; 65 dep = new ll[(n + 1)]; 66 dis = new ll[(n + 1)]; 67 for (int i = 0; i < 2; i++) { 68 ap[i] = new ll[(n + 1)]; 69 cp[i] = new ll[(n + 1)]; 70 } 71 g = MapManager(n, n << 1); 72 memset(vis, false, sizeof(boolean) * (n + 1)); 73 memset(icir, false, sizeof(boolean) * (n + 1)); 74 for (int i = 1, u, v, w; i <= n; i++) { 75 scanf("%d%d%d", &u, &v, &w); 76 g.addEdge(u, v, w); 77 g.addEdge(v, u, w); 78 } 79 } 80 81 boolean getLoop(int p, int fa) { 82 if (vis[p]) { 83 ccir = 0; 84 int cur = 0; 85 do { 86 cur = s.top(); 87 s.pop(); 88 icir[cur] = true; 89 cir[ccir++] = cur; 90 cc = ccir - 1; 91 } while (cur != p); 92 return true; 93 } 94 vis[p] = true; 95 s.push(p); 96 for (int i = g.h[p]; ~i; i = g[i].nx) { 97 int e = g[i].ed; 98 if (e == fa) continue; 99 if (getLoop(e, p)) { 100 if (icir[p]) { 101 nw[cc] = g[i].w; 102 cc = (cc + 1) % ccir; 103 } 104 return true; 105 } 106 } 107 s.pop(); 108 return false; 109 } 110 111 void dfs(int p, int fa, ll dep, int& fn, ll& fd) { 112 if (dep > fd) 113 fd = dep, fn = p; 114 for (int i = g.h[p]; ~i; i = g[i].nx) { 115 int e = g[i].ed; 116 if (e == fa || icir[e]) continue; 117 dfs(e, p, dep + g[i].w, fn, fd); 118 } 119 } 120 121 inline void solve() { 122 getLoop(1, 0); 123 ll fixedd = 0; 124 // for (int i = 0; i < ccir; i++) 125 // cerr << cir[i] << " "; 126 // cerr << endl; 127 // for (int i = 0; i < ccir; i++) 128 // cerr << nw[i] << " "; 129 // cerr << endl; 130 for (int i = 0, fn, fbn; i < ccir; i++) { 131 fn = -1, dep[i] = 0; 132 dep[i] = 0, dfs(cir[i], 0, 0, fn, dep[i]); 133 if (~fn) 134 icir[cir[i]] = false, dfs(fn, 0, 0, fbn, fixedd), icir[cir[i]] = true; 135 } 136 dis[0] = 0; 137 for (int i = 1; i < ccir; i++) 138 dis[i] = nw[i - 1]; 139 for (int i = 1; i < ccir; i++) 140 dis[i] += dis[i - 1]; 141 ll mi = dep[0]; 142 ap[0][0] = -llf, cp[0][0] = dep[0]; 143 for (int i = 1; i < ccir; i++) { 144 ap[0][i] = max(ap[0][i - 1], dep[i] + dis[i] + mi); 145 mi = max(mi, dep[i] - dis[i]); 146 cp[0][i] = max(cp[0][i - 1], dep[i] + dis[i]); 147 } 148 mi = dep[ccir - 1] + dis[ccir - 1]; 149 ap[1][ccir - 1] = -llf, cp[1][ccir - 1] = dep[ccir - 1]; 150 for (int i = ccir - 2; ~i; i--) { 151 ap[1][i] = max(ap[1][i + 1], dep[i] - dis[i] + mi); 152 mi = max(mi, dep[i] + dis[i]); 153 cp[1][i] = max(cp[1][i + 1], dep[i] + dis[ccir - 1] - dis[i]); 154 } 155 ll ans = ap[0][ccir - 1]; 156 for (int i = 0; i < ccir - 1; i++) 157 ans = min(max(max(ap[0][i], ap[1][i + 1]), cp[0][i] + cp[1][i + 1] + nw[ccir - 1]), ans); 158 printf(Auto, max(ans, fixedd)); 159 } 160 161 int main() { 162 init(); 163 solve(); 164 return 0; 165 }