Codeforces 835F Roads in the Kingdom - 动态规划

题目传送门

  传送点I

  传送点II

  传送点III

题目大意

   给定一颗基环树,要求删去其中一条边,使得剩下的图形是一棵树,并且最长路的长度最短,求最长路的最短长度。

  路径可以分为两部分:跨过环 和 在树内部。

  要删除一条边,使图形变为一棵树,那么只能删去环上的一条边,因此,我们无法改变第二部分的路径,但是可以改变第一部分。

  对于第二部分可以通过两次搜索或者树形动态规划解决。

  对于第一部分,考虑枚举删去环上的一条边。但是发现仍然不太方便处理,因为不好维护环上的信息。仍然考虑剖环成链。

  假设环的大小为$k$,从剖点开始依次将所有点标号1到$k$。

  当一条边被删除后,第二部分可能成为答案的情况有两种:

  1. 不跨过剖点和被删边的路径
  2. 跨过剖点但不经过被删边的路径

  因此考虑维护一些数组。

  1. 在$1, 2, \cdots, i$及其所在的树中的最长路。
  2. 从$1$开始,到$1, 2, \cdots, i$及其所在的树中的最长路。
  3. 在$k, k - 1, \cdots, i$及其所在的树中的最长路。
  4. 从$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 }
posted @ 2018-07-01 16:47 阿波罗2003 阅读(...) 评论(...) 编辑 收藏