直径

59percent

2019-07-27 19:16:29

Solution

```cpp /* 直径: 正权求法两次dfs: 1. 任意选一个点做为根,找最长的一个点p1 2. 用p1做根,找最长一个点q, p1->q就是一条直径 2.1 p1做根,找出所有最长的点qi, 2.2 p1 -> qi都是直径,找出p1->qi的公共LCA, lcaq 2.3 任意选一个q1,找出所有最长的点pi lcap lcaq p1 ---- Y-----X-----> q1 p2 ----| |____> q2 |-- q3 3. dep[lcaq] - dep[lcap] -> 边的数目 */ ``` # 朴素算法 ```cpp #include <iostream> #include <vector> #define N 200005 using namespace std; typedef long long ll; struct Edge { int y, w; }; vector<Edge> g[N]; int n, fa[N], dep[N]; ll len[N], mx = 0; int p[N], last; void getMaxs() { last = 0; mx = 0; for (int i = 1; i <= n; i++) mx = max(mx, len[i]); for (int i = 1; i <= n; i++) if (len[i] == mx) p[++last] = i; } void dfs(int x, int _fa, int _dep, ll _len) { fa[x] = _fa; dep[x] = _dep; len[x] = _len; for (int i = 0; i < g[x].size(); i++) { int y = g[x][i].y, w = g[x][i].w; if (y == _fa) continue; dfs(y, x, _dep + 1, _len + w); } } int lca(int x, int y) { if (dep[x] < dep[y]) swap(x, y); while (dep[x] > dep[y]) x = fa[x]; while (x != y) { x = fa[x]; y = fa[y]; } return x; } int getCommonLca() { int x = p[1]; for (int i = 2; i <= last; i++) x = lca(x, p[i]); return x; } int main() { cin >> n; for (int i = 1; i <= n - 1; i++) { int x, y, w; cin >> x >> y >> w; Edge e1 = {y, w}; g[x].push_back(e1); Edge e2 = {x, w}; g[y].push_back(e2); } dfs(1, 0, 1, 0); getMaxs(); dfs(p[1], 0, 1, 0); getMaxs(); int lca_u = getCommonLca(); dfs(p[1], 0, 1, 0); getMaxs(); int lca_v = getCommonLca(); cout << mx << endl; cout << (dep[lca_v] - dep[lca_u]) << endl; return 0; } ``` ![](https://cdn.luogu.com.cn/upload/pic/66165.png) # 正解 ```cpp #include <iostream> #include <vector> #include <cmath> using namespace std; typedef long long ll; struct Edge { int y, w; }; const int N=200005; int n,dep[N],fa[N], lgn, st[N][18]; ll dis[N], mx; int p[N], last; vector<Edge> g[N]; void calcMaxs() { last = 0, mx=0; for(int i=1; i<=n; i++) mx = max(mx, dis[i]); for(int i=1; i<=n; i++) if(dis[i]==mx) p[++last] = i; } void dfs(int x, int _fa, int _dep, ll _dis) { fa[x] = _fa; dep[x] = _dep; dis[x] = _dis; st[x][0] = _fa; for(int i=0; i<g[x].size(); i++) { int y = g[x][i].y, w=g[x][i].w; if(y == _fa) continue; dfs(y, x, _dep+1, _dis+w); } } void initSt() { for(int j=1; j<=lgn; j++) for(int i=1; i<=n; i++) st[i][j] = st[st[i][j-1]][j-1]; } int lca(int x, int y) { if(dep[x]<dep[y]) swap(x, y); /*while(dep[x]>dep[y]) x = fa[x]; while(x!=y) { x = fa[x]; y = fa[y]; }*/ int d = dep[x] - dep[y]; for(int i=0; i<=lgn; i++) if((d>>i)&1) x = st[x][i]; if(x==y) return x; for(int i=lgn; i>=0; i--) { if(st[x][i]==st[y][i]) continue; x = st[x][i]; y = st[y][i]; } return st[x][0]; } int commonLca() { int cl = p[1]; for(int i=2; i<=last; i++) cl = lca(cl, p[i]); return cl; } int main() { cin>>n; lgn = log2(n); for(int i=1; i<=n-1; i++) { int x, y, w; cin>>x>>y>>w; g[x].push_back((Edge){y, w}); g[y].push_back((Edge){x, w}); } //第一个端点u dfs(1, 0, 1, 0); calcMaxs(); int u = p[1]; //第二个端点v dfs(u, 0, 1, 0); calcMaxs(); int v = p[1]; //u为根的时候,p[i]的公共lca initSt(); int lca_u = commonLca(); //v为根的时候,p[i]的公共lca dfs(v, 0, 1, 0); calcMaxs(); initSt(); int lca_v = commonLca(); //求公共边的数目, dep[lca_v]-dep[lca_u] cout<<mx<<endl; cout<<dep[lca_v]-dep[lca_u]<<endl; return 0; } ```