题目

小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. windows的cmd和git bash的常用命令

    windows下使用git bash,使用的事linux下的命令,整理常用命令如下: windows下的命令 linux下的命令 命令的含义 cd e:\xx cd /e/xx 切换到xx目录 cd ...

  2. Clown without borders 2017/1/9

    原文 Taking laughter to those who need it most "When will you all return again?"the Croatian ...

  3. mysql Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nona

    1. 操作mysql的时候提示如下错误 [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and cont ...

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

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

  5. CPP-基础:函数指针,指针函数,指针数组

    函数指针 函数指针是指向函数的指针变量. 因而“函数指针”本身首先应是指针变量,只不过该指针变量指向函数.这正如用指针变量可指向整型变量.字符型.数组一样,这里是指向函数.如前所述,C在编译时,每一个 ...

  6. jExcelAPI导入导出excel

      MS的电子表格(Excel)是Office的重要成员,是保存统计数据的一种常用格式.作为办公文档,势必要涉及到的电子文档的交换,Excel是一种在企业中非常通用的文件格式,打印和管理也比较方便.在 ...

  7. fckeditor配置详解

    使用配置设置: . FCKConfig.CustomConfigurationsPath = '' ; // 自定义配置文件路径和名称 . FCKConfigFCKConfig.EditorAreaC ...

  8. 四. python网络编程

    第八章.网络基础知识 1. TCP/IP协议介绍 1.TCP/IP概念 TCP/IP: Transmission Control Protocol/Internet Protocol的简写,中译名为传 ...

  9. 设置tableview的滚动范围--iOS开发系列---项目中成长的知识三

    设置tableview的滚动范围 有时候tableview的footerview上的内容需要向上拖动界面一定距离才能够看见, 项目中因为我需要在footerviw上添加一个按钮,而这个按钮又因为这个原 ...

  10. sudo指令和/etc/sudoers文件说明

    sudo 命令 -l 显示当前用户的sudo权限-l username 显示username的sudo权限-u username 以username的权限执行-k 强迫用户下一次执行sudo时问密码( ...