Codeforces 835 F. Roads in the Kingdom
阿新 • • 發佈:2018-07-12
問題 深度 oid temp def val com out opera 個點到環左端點的距離,\(dep_i\) 為 環上第 \(i\) 個點對應的外向樹的最大深度
\(>Codeforces\space835 F. Roads in the Kingdom<\)
題目大意 : 給你一棵 \(n\) 個點構成的樹基環樹,你需要刪掉一條環邊,使其變成一顆樹,並最小化刪掉環邊後的樹的直徑。
\(n \leq 2 \times 10^5\) 樹的邊權 $ \leq 10^9 $
解題思路 :
考慮最終樹的直徑可能由兩部分組成,答案是其中的最大值
第一種就是外向樹內的直徑的最大值,這個只需要隨便\(dp\)一下即可,這裏不過多討論
第二種情況樹的直徑經過原來的環,必然是環上的一段加上兩端對應的外向樹的 \(maxdep\)
設 \(l_i\) 為將環展開後環上第 \(i\)
設選取的環的左端點為 \(x\) 右端點為 \(y\) ,那麽經過環上 \(x \rightarrow y\) 一段的樹的直徑就是可以表示為
\(l_y - l_x + dep_x + dep_y\)
問題自此轉化為對於每一種把環展開的方式,求 \(\max(l_y - l_x + dep_x + dep_y)\)
即 \(\max(l_y + dep_y) - \min(l_x - dep_x) \ y \neq x\) 用兩個\(set\) 分別維護即可
/*program by mangoyang*/ #include<bits/stdc++.h> #define inf (0x7f7f7f7f) #define Max(a, b) ((a) > (b) ? (a) : (b)) #define Min(a, b) ((a) < (b) ? (a) : (b)) typedef long long ll; using namespace std; template <class T> inline void read(T &x){ int f = 0, ch = 0; x = 0; for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = 1; for(; isdigit(ch); ch = getchar()) x = x * 10 + Qch - 48; if(f) x = -x; } #define int ll #define N (600005) int a[N], b[N], head[N], nxt[N], cnt; int st[N], ct[N], vis[N], success; int g[N], dep[N], c[N], s[N], tot, top, n; struct Node{ int val, id; bool operator < (const Node &A) const{ return val < A.val; } }; multiset<Node> s1, s2; inline void add(int x, int y, int z){ a[++cnt] = y, b[cnt] = z; nxt[cnt] = head[x], head[x] = cnt; } inline void Getcircle(int u, int fa){ vis[u] = 1; for(int p = head[u]; p; p = nxt[p]){ int v = a[p]; if(v == fa) continue; if(!vis[v]){ st[++top] = v, ct[top] = b[p]; Getcircle(v, u); } else{ int pos = 1; for(int i = 1; i <= top; i++) if(st[i] == v){ pos = i; break; } for(int i = pos; i <= top; i++) c[++tot] = st[i], s[tot] = ct[i]; s[1] = b[p]; return (void) (success = 1); } if(success) return; } if(success) return; vis[u] = 0, top--; } inline int dfs(int u, int fa){ int mx = u; for(int p = head[u]; p; p = nxt[p]){ int v = a[p]; if(v != fa && !vis[v]){ dep[v] = dep[u] + b[p]; int now = dfs(v, u); if(dep[now] > dep[mx]) mx = now; } } return mx; } inline int dfs2(int u, int fa, int dis, int t){ int res = dis; for(int p = head[u]; p; p = nxt[p]){ int v = a[p]; if(v != fa){ if(vis[v] && t) continue; if(!vis[v]){ int now = dfs2(v, u, dis + b[p], t); if(now > res) res = now; } else{ int now = dfs2(v, u, dis + b[p], 1); if(now > res) res = now; } } } return res; } inline ll calc1(){ multiset<Node>::iterator it2 = s2.begin(); int id = it2 -> id; s1.erase(s1.find((Node){s[id] + g[id], id})); multiset<Node>::iterator it1 = s1.end(); it1--; int ans = it1 -> val - it2 -> val; s1.insert((Node){s[id] + g[id], id}); return ans; } inline ll calc2(){ multiset<Node>::iterator it1 = s1.end(); it1--; int id = it1 -> id; s2.erase(s2.find((Node){s[id] - g[id], id})); multiset<Node>::iterator it2 = s2.begin(); int ans = it1 -> val - it2 -> val; s2.insert((Node){s[id] - g[id], id}); return ans; } inline ll calc(){ return max(calc1(), calc2()); } main(){ read(n); if(n <= 2) return puts("0"), 0; for(int i = 1, x, y, z; i <= n; i++){ read(x), read(y), read(z); add(x, y, z), add(y, x, z); } ll ans = 0; st[++top] = 1, Getcircle(1, 0); for(int i = 1; i <= n; i++) vis[i] = 0; for(int i = 1; i <= tot; i++) vis[c[i]] = 1; for(int i = 1; i <= tot; i++){ int mx = dfs(c[i], 0); g[i] = dep[mx], ans = max(ans, g[i]); ans = max(ans, dfs2(mx, 0, 0, mx == c[i] ? 1 : 0)); } for(int i = 1; i <= tot; i++) g[i+tot] = g[i]; for(int i = 1; i <= tot; i++) s[i+tot] = s[i]; tot *= 2; for(int i = 1; i <= tot; i++) s[i] += s[i-1]; for(int i = 1; i <= tot / 2; i++){ s1.insert((Node){s[i] + g[i], i}); s2.insert((Node){s[i] - g[i], i}); } ll tmp = calc(); for(int i = 2; i <= tot / 2; i++){ int l = i, r = i + tot / 2 - 1; s1.insert((Node){s[r] + g[r], r}); s2.insert((Node){s[r] - g[r], r}); s1.erase(s1.find((Node){s[l-1] + g[l-1], l - 1})); s2.erase(s2.find((Node){s[l-1] - g[l-1], l - 1})); tmp = min(tmp, calc()); } cout << Max(ans, tmp); return 0; }
Codeforces 835 F. Roads in the Kingdom