3124: [Sdoi2013]直径
3124: [Sdoi2013]直径
https://www.lydsy.com/JudgeOnline/problem.php?id=3124
分析:
所有直径都经过的边,一定都是连续的一段。(画个图,反证一下)
然后可以求出一条直径后,可以对每个点求出不经过直径到达的最远的距离。
然后判断一下,找到左边分叉的最后一个,右边分叉的第一个,中间的点就是所有直径都经过的点。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 inline int read() { 6 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 7 for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 8 } 9 10 const int N = 200100; 11 12 int head[N], q[N], fa[N], nxt[N<<1], to[N<<1], Enum; 13 LL dis[N], dist[N], val[N<<1], Len = 0, Mx = 0; 14 int Root, Qd, Zd, tot; 15 bool vis[N]; 16 17 inline void add_edge(int u,int v,int w) { 18 ++Enum; to[Enum] = v; val[Enum] = w; nxt[Enum] = head[u]; head[u] = Enum; 19 ++Enum; to[Enum] = u; val[Enum] = w; nxt[Enum] = head[v]; head[v] = Enum; 20 } 21 22 void dfs1(int u,int pa) { 23 fa[u] = pa; 24 if (dis[u] > Len) { 25 Len = dis[u]; Root = u; 26 } 27 for (int i=head[u]; i; i=nxt[i]) { 28 int v = to[i]; 29 if (v == pa) continue; 30 dis[v] = dis[u] + val[i]; 31 dfs1(v, u); 32 } 33 } 34 35 void dfs2(int u,int pa) { 36 vis[u] = true; 37 if (dist[u] > Mx) { 38 Mx = dist[u]; Root = u; 39 } 40 for (int i=head[u]; i; i=nxt[i]) { 41 int v = to[i]; 42 if (v == pa || vis[v]) continue; 43 dist[v] = dist[u] + val[i]; 44 dfs2(v, u); 45 } 46 } 47 48 int main() { 49 50 int n = read(); 51 for (int i=1; i<n; ++i) { 52 int u = read(), v = read(), w = read(); 53 add_edge(u, v, w); 54 } 55 dfs1(1, 0); 56 Len = 0; Qd = Root; dis[Qd] = 0; 57 dfs1(Root, 0); 58 Zd = Root; 59 60 for (int i=Zd; i; i=fa[i]) q[++tot] = i, vis[i] = true; 61 62 int L = tot, R = 1; 63 for (int i=tot; i>=1; --i) { 64 Mx = 0;dfs2(q[i], 0); 65 if (!Mx) continue; 66 if (Mx == dis[q[i]]) L = i; // 保证所有直径都经过,左边分叉的最后一个 67 if (Len - dis[q[i]] == Mx) {R = i; break;} // 右边分叉的第一个 68 } 69 cout << Len << "\n" << L - R; 70 return 0; 71 }