一些树上问题的解题报告
树的直径问题
luogu P3304 直径
分析
板子题,可以证明所有的直径都经过的边是几条连续的边
那么只需要找出任意一条直径,对于直径上的任意一个点,以这个点作为根节点做一次dfs
如果以该点为起点的路径(不经过原直径上的点)最长长度等于它到原直径某一段端点的长度,就说明从该点到这一端点的这一段都不是必须被经过的。
假设从直径左端到右端遍历,那么在遍历过程中找到的第一个满足 路径最长长度等于到直径右端端点长度 的点,
从该点到最右端之间的边都不是必须经过的;
而在遍历过程中找到的路径最长长度等于到直径左端端点长度的点,只能保证当前节点之前的路径是不必须经过的。
下面证明所有的直径都经过的边必然连续:
假设这样的边不连续,那么不妨在脑海里画一个图,本来是一条直径,脑海里画一条直线,根据假设,所有直径都经过的边不连续,
不妨把这条直径中间拉开,使得这条直径分为上下两边,必然满足假设的情况,然而这样必然成环,与树的结构矛盾。
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
#define rg register
#define IOS ios::sync_with_stdio(false);cin.tie(NULL),cout.tie(NULL)
/*inline int read(){
rg int x = 0, f = 1;
rg char c = getchar();
while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();}
while (c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
return x * f;
}*/
#define ll long long
const int N = 2e5 + 7;
struct Edge{
int to, val, next;
}e[N << 1];
int head[N], tot;
inline void add(int u, int v, int w){
e[++tot].to = v, e[tot].val = w, e[tot].next = head[u];
head[u] = tot;
}
int pathleft, pathright, templ;
ll maxd, dep[N];
int f[N];
bool ondis[N];
int ansl, ansr;
void dfs1(int u, int fa){
f[u] = fa;
for (int i(head[u]); i; i = e[i].next){
int w = e[i].val, v = e[i].to;
if (v == fa) continue;
dep[v] = dep[u] + w;
if (dep[v] > maxd){
maxd = dep[v];
templ = v;
}
dfs1(v, u);
}
}
void dfs2(int u, int fa){
for (int i(head[u]); i; i = e[i].next){
int w = e[i].val, v = e[i].to;
if (v == fa || ondis[v]) continue;
dep[v] = dep[u] + w;
if (dep[v] > maxd){
maxd = dep[v];
}
dfs2(v, u);
}
}
int main(){
IOS;
//freopen("in.txt", "r", stdin);
int n;
cin >> n;
for (int i(1); i < n; ++i){
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
dfs1(1, 0);
pathleft = templ;
dep[pathleft] = 0, maxd = 0;
dfs1(pathleft, 0);
pathright = templ;
ansl = pathleft, ansr = pathright;
cout << maxd << endl;
for (int i(pathright); i; i = f[i]) ondis[i] = true;
bool flag = true;
for (int i(f[pathright]); i != pathleft; i = f[i]){
int leftdis = dep[i], rightdis = dep[pathright] - dep[i];
maxd = dep[i] = 0;
dfs2(i, 0);
if (maxd == rightdis) ansr = i;
else if (maxd == leftdis && flag) flag = false, ansl = i;
}
int ans = 0;
for (int i(ansr); i != ansl; i = f[i]) ++ans;
cout << ans;
return 0;
}