题目描述
小 Q 最近学习了一些图论知识。根据课本,有如下定义。树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度。如果一棵树有 N 个节点,可以证明其有且仅有 N−1 条边。
路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用 dis(a,b) 表示点 a 和点 b 的路径上各边长度之和。称dis(a,b) 为 a,b 两个节点间的距离。
直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。
现在小 Q 想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。
输入格式
第一行包含一个整数 N,表示节点数。
接下来 N−1 行,每行三个整数 a,b,c,表示点 a 和点 b 之间有一条长度为 c 的无向边。
输出格式
共两行。第一行一个整数,表示直径的长度。第二行一个整数,表示被所有直径经过的边的数量。
输入输出样例
输入 #1
6 3 1 1000 1 4 10 4 2 100 4 5 50 4 6 100
输出 #1
1110 2
说明/提示
【样例说明】
直径共有两条,3 到 2的路径和 3 到 6 的路径。这两条直径都经过边 (3,1) 和边(1,4)。
对于 100%的测试数据:2≤N≤2e5,所有点的编号都在 1∼N 的范围内,边的权值 ≤1e9。
解题思路
第一问求树的直径长度,我们可以直接套用模板,做两遍dfs。
第二问求所有直径经过的边的数量。那我们求出所有直径重合的这一段路径的边的数量,就是最终答案。
求法:
由于这条路径是在树上,所以只需要求出这条路径的两个端点即可,这端点就是各直径在这条重合路径同侧端点的LCA。
例子 在样例中有两条直径 3 1 4 2和3 1 4 6,3 1 4为重合路径,其左端只有端点3所以3为重合路径的左端点,其右端有2 6两个端点,所以求出2 6的LCA为4,节点4即为重合路径的右端点。再求出3 4 之间的路径条数即可。
我们可以定义两个数组dep(深度)和len(长度),dep表示其余节点与根节点之间的边条数,len表示其余节点与根节点之间的路径长度。第一遍dfs求出距根节点1最长的节点u;第二遍dfs以u(记u为一条直径的左端点)为根节点,找到所有直径的右端点,求出右端点们的LCA(记为v);第三遍dfs以v为根节点向左搜索,找到所有直径的左端点,求出左端点们的LCA(记为w)。此时以v为根节点的w的深度就是最终答案。
AC_Code
#include<bits/stdc++.h>
#include<iostream>
#include<vector>
#include<queue>
using namespace std;
using ll = long long;
const int N = 2e5 + 5;
typedef pair<ll, ll>PII;
vector<PII>g[N];
queue<int>b1, b2;
int dep[N], depu[N],depv[N], parent[N][20], parentu[N][20], parentv[N][20];
ll len[N], lenu[N], lenv[N];
void dfs(int x, int p, int dep[],ll len[], int parent[][20]) {
for (int i = 1; i < 20; ++i) {
parent[x][i] = parent[parent[x][i - 1]][i - 1];
}
dep[x] = dep[p] + 1;
for (auto&y : g[x]) {
if (y.first != p) {
len[y.first] = len[x] + y.second;
parent[y.first][0] = x;
dfs(y.first, x, dep, len, parent);
}
}
}
//倍增求LCA
int lca(int a, int b, int dep[], int parent[][20]) {
if (dep[a] < dep[b])swap(a, b);
for (int i = 19; i >= 0; --i) {
if (dep[a] - (1 << i) >= dep[b])
a = parent[a][i];
}
if (a == b)return a;
for (int i = 19; i >= 0; --i) {
if (parent[a][i] != parent[b][i]) {
a = parent[a][i];
b = parent[b][i];
}
}
return parent[a][0];
}
int main() {
int n; cin >> n;
for (int i = 1; i < n; ++i) {
int a, b, c; cin >> a >> b >> c;
g[a].push_back({ b,c });
g[b].push_back({ a,c });
}
int u = 0, v = 0,w=0;
dep[0] = -1;
dfs(1, 0, dep,len,parent);
for (int i = 1; i <= n; ++i)
if (len[i] > len[u])u = i;
depu[0] = -1;
dfs(u, 0, depu, lenu,parentu);
ll ans = *max_element(lenu + 1, lenu + 1 + n);
for (int i = 1; i <= n; ++i)
if (lenu[i] == ans)
b2.push(i);
while (b2.size() != 1) {
int a = b2.front(); b2.pop();
int b = b2.front(); b2.pop();
int c = lca(a, b,depu,parentu);
b2.push(c);
}
v = b2.front();
depv[0] = -1;
dfs(v, 0, depv, lenv, parentv);
ll ansv = *max_element(lenv + 1, lenv + 1 + n);
for (int i = 1; i <= n; ++i)
if (lenv[i] == ansv)b1.push(i);
while (b1.size() != 1) {
int av = b1.front(); b1.pop();
int bv = b1.front(); b1.pop();
int cv = lca(av, bv, depv, parentv);
b1.push(cv);
}
w = b1.front();
cout << ans << '\n';
cout<<depv[w]<<'\n';
}