树的直径模板题,需要考虑的是第二问,求所有直径的公用边,先找出一条直径来,画图思考一下会发现,如果这条树的直径上面有个点可以找出另一条直径来,那么这个点以前的边就至少和这一条新找出的直径
不共用,那么也就是求两个端点开始最后是从哪里分叉的。从一个端点沿着直径找,直到发现延伸到另一个端点的直径,思考一下会发现这个其实就是另一个端点的最后一个分叉点,并且这个端点的延伸直径也已经找完了,如果你还能找到这个端点的分叉点,那么说明你直径找错了!!!因为还能找到就说明有更长的直径。
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define int long long
using namespace std;
const int maxn = 2e5 + 7;
struct node
{
int next, to, val;
};
node edge[maxn<<1];
int vis[maxn], dis[maxn], num[maxn], head[maxn], f[maxn], deep[maxn];
int tot, ans, poi;
void add(int u, int v, int w)
{
edge[tot] = (node){head[u], v, w};
head[u] = tot++;
}
void dfs(int x, int fa)
{
f[x] = fa;
if(ans < dis[x])
{
ans = dis[x];
poi = x;
}
for(int i = head[x]; ~i; i = edge[i].next)
{
int to = edge[i].to;
if(to == fa)
continue;
dis[to] = dis[x] + edge[i].val;
dfs(to, x);
}
}
int getpath(int u)
{
int cnt = 0;
while(u != 0)
{
vis[u] = 1;
num[++cnt] = u;
u = f[u];
}
return cnt;
}
void dfs1(int u, int fa)
{
if(deep[u] > ans)
ans = deep[u];
for(int i = head[u]; ~i; i = edge[i].next)
{
int v = edge[i].to;
if(vis[v] || v == fa)
continue;
deep[v] = deep[u] + edge[i].val;
dfs1(v, u);
}
}
signed main()
{
int n;
scanf("%lld", &n);
memset(head, -1, sizeof(head));
for(int i = 1; i < n; i++)
{
int u, v, w;
scanf("%lld%lld%lld", &u, &v, &w);
add(u, v, w);
add(v, u, w);
}
int p, q;
ans = 0;
dis[1] = 0;
dfs(1, 0);
p = poi;
ans = 0;
dis[p] = 0;
dfs(p, 0);
int len = ans;
q = poi;
int l = getpath(q);
int r = 1;
int m = l;
for(int i = m; i >= 1; i--)
{
ans = 0;
dfs1(num[i], 0);
if(!ans)
continue;
if(ans == dis[num[i]])
l = i;
else if(ans == len - dis[num[i]])
{
r = i;
break;
}
}
printf("%lld\n", len);
printf("%lld\n", l - r);
return 0;
}