题目

小Q最近学习了一些图论知识。根据课本,有如下定义。树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度。如果一棵树有N个节点,可以证明其有且仅有N-1 条边。 路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用 dis(a,b)

表示点a和点b的路径上各边长度之和。称dis(a,b)为a、b两个节点间的距离。

直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。

现在小Q想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。

输入格式

第一行包含一个整数N,表示节点数。

接下来N-1行,每行三个整数a, b, c ,表示点 a和点b之间有一条长度为c

的无向边。

输出格式

共两行。第一行一个整数,表示直径的长度。第二行一个整数,表示被所有

直径经过的边的数量。

输入样例

6

3 1 1000

1 4 10

4 2 100

4 5 50

4 6 100

输出样例

1110

2

提示

【样例说明】

直径共有两条,3 到2的路径和3到6的路径。这两条直径都经过边(3, 1)和边(1, 4)。

对于100%的测试数据:2≤N≤200000,所有点的编号都在1..N的范围内,

边的权值≤10^9。

题解

首先我们先求出树的直径,解决问题1

然后对于这条我们任意找出的直径,答案一定在这条直径上,因为其它直径对于这条直径来说,没有被访问到

我们就看看这条直径上还有那些直径经过

我们求出直径上每个点的外向树到这条直径的最远距离

如果存在一个点的最远距离 + 次远距离 = 直径长,那么答案是0

否则求出直径上每个点向左能延伸的最远距离及该距离下最近的拐点,向右也求出

记为ml,mr,拐点记为pre和post,直径长为L

如果\(ml + mr = L\),说明有一条直径经过区间\([pre,post]\),那么区间外的边一定不是答案

如此反复,我们得到若干个区间,排个序取公共部分就是答案

埋头乱码竟1A,,

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 200005,maxm = 400005,INF = 100000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int h[maxn],ne = 2;
struct EDGE{int to,nxt,w;}ed[maxm];
inline void build(int u,int v,int w){
ed[ne] = (EDGE){v,h[u],w}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v],w}; h[v] = ne++;
}
int n,rt,fa[maxn],c[maxn],vis[maxn],tot;
LL d[maxn],sum[maxn],ansL;
void dfs1(int u){
if (d[u] > d[rt]) rt = u;
Redge(u) if ((to = ed[k].to) != fa[u]){
d[to] = d[u] + ed[k].w; fa[to] = u;
dfs1(to);
}
}
void solve1(){
dfs1(1);
d[rt] = 0; fa[rt] = 0;
dfs1(rt);
for (int i = rt; i; i = fa[i]){
c[++tot] = i;
sum[tot] = d[i];
vis[i] = true;
}
reverse(c + 1,c + 1 + tot);
reverse(sum + 1,sum + 1 + tot);
printf("%lld\n",ansL = d[rt]);
}
LL gmax,hmax,md[maxn],ml[maxn],mr[maxn];
int pre[maxn],post[maxn];
void dfs2(int u){
if (d[u] >= gmax){
hmax = gmax;
gmax = d[u];
}
else if (d[u] > hmax){
hmax = d[u];
}
vis[u] = true;
Redge(u) if (!vis[to = ed[k].to]){
d[to] = d[u] + ed[k].w;
dfs2(to);
}
}
struct inter{int l,r;}e[2 * maxn];
int cnt,tag[maxn];
inline bool operator <(const inter& a,const inter& b){
return a.l == b.l ? a.r < b.r : a.l < b.l;
}
void solve2(){
for (int i = 1; i <= tot; i++){
gmax = hmax = -INF; d[c[i]] = 0;
dfs2(c[i]);
md[i] = gmax;
if (gmax + hmax == ansL){
puts("0");
return;
}
}
ml[1] = md[1]; pre[1] = 1;
for (int i = 2; i <= tot; i++){
if (md[i] >= ml[i - 1] + sum[i] - sum[i - 1]){
pre[i] = i;
ml[i] = md[i];
}
else {
pre[i] = pre[i - 1];
ml[i] = ml[i - 1] + sum[i] - sum[i - 1];
}
}
mr[tot] = md[tot]; post[tot] = tot;
for (int i = tot - 1; i; i--){
if (md[i] >= mr[i + 1] + sum[i + 1] - sum[i]){
post[i] = i;
mr[i] = md[i];
}
else {
post[i] = post[i + 1];
mr[i] = mr[i + 1] + sum[i + 1] - sum[i];
}
}
for (int i = 1; i <= tot; i++){
if (pre[i] == post[i]) continue;
if (ml[i] + mr[i] == ansL){
e[++cnt] = (inter){1,pre[i]};
e[++cnt] = (inter){post[i],tot};
}
}
sort(e + 1,e + 1 + cnt);
int l = 0,r = -1;
for (int i = 1; i <= cnt; i++){
if (e[i].l > r + 1){
for (int j = l; j <= r; j++) tag[j] = true;
l = e[i].l;
r = e[i].r;
}
else r = max(r,e[i].r);
}
for (int j = l; j <= r; j++) tag[j] = true;
int ans = 0;
for (int i = 1; i <= tot; i++){
if (i != 1 && i != tot && !tag[i]){
ans++;
if (tag[i - 1]) ans++;
}
}
printf("%d\n",ans);
}
int main(){
n = read();
int a,b,w;
for (int i = 1; i < n; i++){
a = read(); b = read(); w = read();
build(a,b,w);
}
solve1();
solve2();
return 0;
}

BZOJ3124 [Sdoi2013]直径 【树的直径】的更多相关文章

  1. POJ 1985.Cow Marathon-树的直径-树的直径模板(BFS、DFS(vector存图)、DFS(前向星存图))

    Cow Marathon Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 7536   Accepted: 3559 Case ...

  2. [SDOI2013]直径 (树的直径,贪心)

    题目链接 Solution 我们直接找到一条直径 \(s\),起点为 \(begin\),终点为 \(end\). 从前往后遍历点 \(u\) ,若子树中最大的距离与 \(dis(u,begin)\) ...

  3. 树形DP 学习笔记(树形DP、树的直径、树的重心)

    前言:寒假讲过树形DP,这次再复习一下. -------------- 基本的树形DP 实现形式 树形DP的主要实现形式是$dfs$.这是因为树的特殊结构决定的——只有确定了儿子,才能决定父亲.划分阶 ...

  4. bzoj3124: [Sdoi2013]直径 树形dp two points

    题目链接 bzoj3124: [Sdoi2013]直径 题解 发现所有直径都经过的边 一定在一条直径上,并且是连续的 在一条直径上找这段区间的两个就好了 代码 #include<map> ...

  5. bzoj千题计划134:bzoj3124: [Sdoi2013]直径

    http://www.lydsy.com/JudgeOnline/problem.php?id=3124 第一问: dfs1.dfs2 dfs2中记录dis[i]表示点i距离最长链左端点的距离 第二问 ...

  6. 2018.11.05 bzoj3124: [Sdoi2013]直径(树形dp)

    传送门 一道sbsbsb树形dpdpdp 第一问直接求树的直径. 考虑第二问问的边肯定在同一条直径上均是连续的. 因此我们将直径记下来. 然后对于直径上的每一个点,dpdpdp出以这个点为根的子树中不 ...

  7. SDOI2013直径(树的直径)

    题目描述: 点这里 题目大意: 就是在一个树上找其直径的长度是多少,以及有多少条边满足所有的直径都经过该边. 题解: 首先,第一问很好求,两边dfs就行了,第一次从任一点找距它最远的点,再从这个点找距 ...

  8. poj2631 求树的直径裸题

    题目链接:http://poj.org/problem?id=2631 题意:给出一棵树的两边结点以及权重,就这条路上的最长路. 思路:求实求树的直径. 这里给出树的直径的证明: 主要是利用了反证法: ...

  9. poj1985 Cow Marathon (求树的直径)

    Cow Marathon Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 3195   Accepted: 1596 Case ...

随机推荐

  1. Selenium私房菜系列9 -- 我遇到的问题及解决问题的方法

    Selenium私房菜系列10 -- 我遇到的问题及解决问题的方法

  2. openssl安装介绍

    #因CentOS7默认安装了openssl1.0版本,需要删除该版本,才能安装openssl.1.0.2l版本yum remove -y openssl openssl-devel cd /usr/l ...

  3. Android学习总结(九)———— 内容提供器(ContentProvider)

    一.内容提供器基本概念 内容提供器主要用于在不同的应用程序之间实现数据共享的功能,它提供了一套完整的机制,允许一个程序访问另一个程序中的数据,同时还能保证被访数据的安全性.详细资料请看下图: 二.示例 ...

  4. (十二)maven之nexus仓库的基本用法

    nexus仓库的基本用法 ① 启动nexus. 上一章有提到:https://www.cnblogs.com/NYfor2018/p/9079068.html ② 访问http://localhost ...

  5. Android串口通信

    前段时间因为工作需要研究了一下android的串口通信,网上有很多讲串口通信的文章,我在做的时候也参考了很多文章,现在就将我学习过程中的一些心得分享给大家,希望可以帮助大家在学习的时候少走一些弯路,有 ...

  6. (转)linux自动备份oracle数据库并上传到备份服务器 脚本实现

    实际项目中,备份数据是不可缺少的一步,完成数据的自动备份减少个人的工作量,是我们的目标.之前很少写过脚本,不过这些简单的操作还是可以做到的!话不多说,开始具体介绍:oracle版本:10.2.0操作系 ...

  7. The - Modcrab——使用贪心策略

    一.题目信息 The - Modcrab 简单翻译一下:Vova有生命值h1,每次攻击值为a1,每瓶药水恢复生命值c1;Modcrab有生命值h2,每次攻击值为a2.在每个关卡开始,Vova有两种选择 ...

  8. WPF知识点全攻略10- 路由事件

    路由事件是WPF不得不提,不得不会系列又一 先来看一下他的定义: 功能定义:路由事件是一种可以针对元素树中的多个侦听器(而不是仅针对引发该事件的对象)调用处理程序的事件. 实现定义:路由事件是一个 C ...

  9. vue 不支持 数组Array,只支持get set push,但是正是做tab的时候,用到splice,就都不好用了,最后用v-if,从新渲染 完美解决

    vue 不支持 数组Array,只支持get set push,但是正是做tab的时候,用到splice,就都不好用了,最后用v-if,从新渲染 完美解决

  10. idea Please specify commit message

    在idea中使用github来进行版本控制的时候, 当点击提交的时候遇到了这个问题 错误: Please specify commit message 解决方法: 在commit message中填写 ...