Description:
求树的直径的必须边
思路:求出任意一条直径,然后对这条直径的每个点进行DFS(不过直径任何点),定义一个l,r,初始为直径的两端,然后计算出该点能到的最远距离如果等于其左端或右端,那么l = pos 或者 r = pos。
注意因为是从右向左搜的,所以左边的点只要收一次,且越早越好。
#include<iostream> #include<cstring> #include<cstdio> using namespace std; const int N = 1e6 + 10; int head[N], now = 1; struct edges{ int to, next, w; }edge[N<<1]; void add(int u, int v, int w){ edge[++now] = {v, head[u], w}; head[u] = now;} int n, m, pre[N], tot, pos1, pos2; bool isd[N]; long long dep[N], mx; void dfs1(int x){ for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(pre[x] == v) continue; pre[v] = x; dep[v] = dep[x] + edge[i].w; dfs1(v); } } void dfs(int x, int fa){ for(int i = head[x]; i; i = edge[i].next){ int v = edge[i].to; if(v == fa || isd[v]) continue; dep[v] = dep[x] + edge[i].w; mx = max(dep[v], mx); dfs(v, x); } } int main(){ scanf("%d", &n); for(int i = 1; i < n; i++){ int x, y, z; scanf("%d%d%d", &x, &y, &z); add(x, y, z); add(y, x, z); } dfs1(1); mx = 0; for(int i = 1; i <= n; i++) if(dep[i] > mx) mx = dep[i], pos1 = i; memset(dep, 0, sizeof(dep)); memset(pre, 0, sizeof(pre)); dfs1(pos1); mx = 0; for(int i = 1; i <= n; i++) if(dep[i] > mx) mx = dep[i], pos2 = i; for(int i = pos2; i; i = pre[i]) isd[i] = 1; bool flag = 0; int l = pos1, r = pos2; long long ans = dep[pos2] - dep[pos1]; for(int i = pre[pos2]; i != pos1; i = pre[i]){ dfs(i, -1); int ls = dep[i], rs = dep[pos2] - dep[i]; dep[i] = mx = 0; dfs(i, -1); if(mx == rs) r = i; if(mx == ls && !flag) flag = 1, l = i; } for(int i = r; i != l; i = pre[i]) tot++; printf("%lld\n%d\n",ans, tot); return 0; }