洛谷 P3304 [SDOI2013]直径(树的直径,最近公共祖先LCA)

[SDOI2013]直径

题目描述

小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

样例输入 #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<=200000,所有点的编号都在1…N的范围内,边的权值<=10^9。

1、 求树的直径,套用模板,求出直径两个端点A 和 B, 直径 = len。关键是直径经过的必须边。
2、 以A为根,求出 与A的距离 = 直径len 的所有点, 假如是 vector<int> VB;
	对  vector<int> VB 的所有点求最近公共祖先 lca1
	
3、 以B为根,求出 与B的距离 = 直径len 的所有点, 假如是 vector<int> VA;
	对  vector<int> VA 的所有点求最近公共祖先 lca2	

4、最后求 lca1 和 lca2 两点之间有多少边
算法竞赛进阶指南, 图论习题8
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 10, M = 4e5 + 10;
int head[N], ver[M], Next[M], edge[M];
int n, m, tot, t;	// t = (int)(log(n) / log(2)) + 1;
ll d1[N], d2[N];	
int A, B;			//树的直径的两个端点
bool vis[N];
ll maxlen;
ll d0[N];

int deep[N];	//节点的深度
int f[N][20];	//f[i][k] 表示节点i向上走 2^k 步
vector<int> VA, VB;	// VB 包含的点 VB[i] 是和 点A 匹配成为 直径的
int lca1, lca2;

void add(int x, int y, int z)
{
   
	ver[++tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
}

void bfs(int root)
{
   
	memset(deep
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值