[NOI2003]逃学的小孩 题解
前言
>原题传送门(洛谷)<
看了一下洛谷题面,这道NOI的题竟然是蓝的(恶评?),做了一下好像确实是蓝的...
解法
思路非常简单,找道树的直径,然后答案是直径长度加上最大的min(dis[pos1], dis[pos2]),pos1和pos2是指定的任意一条直径的两个端点,dis是距离
证明
鉴于这是一棵树(原题面:可以保证,任两个居住点间有且仅有一条通路。)
因此,我们最大的方案必然包含一条直径
可以稍加思考,如果不是直径的话一定能找到一种取直径的方法比它更大...
那么再任意找另一个点,因为要满足"如果A距离C比B距离C近走A,否则走B",所以任意一个点的贡献为min(dis[pos1], dis[pos2])。
题目要求最大的,所以取最大的min(dis[pos1], dis[pos2])
代码
树的直径显然只需要一个DFS,求解也只需要一个DFS,所以共计两个DFS
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
ll read(){
ll x = 0; int zf = 1; char ch = ' ';
while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;
}
struct Edge{
int to, next;
ll dis;
} edges[400005];
int head[200005], edge_num;
void addEdge(int u, int v, ll w){
edges[++edge_num] = {v, head[u], w};
head[u] = edge_num;
}
ll dis[200005];
ll dis2[200005][2];
void getDis(int u, int fa, ll vl){
int v; dis[u] = ((u == fa) ? 0 : dis[fa] + vl);
for (int c_e = head[u]; c_e; c_e = edges[c_e].next){
v = edges[c_e].to; if (v == fa) continue;
getDis(v, u, edges[c_e].dis);
}
}
void getDis2(int u, int fa, ll vl, int op){
int v; dis2[u][op] = ((u == fa) ? 0 : dis2[fa][op] + vl);
for (int c_e = head[u]; c_e; c_e = edges[c_e].next){
v = edges[c_e].to; if (v == fa) continue;
getDis2(v, u, edges[c_e].dis, op);
}
}
int main(){
int n = read(), m = read();
for (int i = 1; i <= m; ++i){
int u = read(), v = read(); ll w = read();
addEdge(u, v, w), addEdge(v, u, w);
}
getDis(1, 1, 0);
int pos1; ll _max = -1;
for (int i = 1; i <= n; ++i)
if (dis[i] > _max)
_max = dis[i], pos1 = i;
getDis(pos1, pos1, 0);
int pos2; _max = -1;
for (int i = 1; i <= n; ++i)
if (dis[i] > _max)
_max = dis[i], pos2 = i;
getDis2(pos1, pos1, 0, 0);
getDis2(pos2, pos2, 0, 1);
ll _max2 = -1;
for (int i = 1; i <= n; ++i)
_max2 = max(_max2, ((dis2[i][0] > dis2[i][1]) ? dis2[i][1] : dis2[i][0]));
printf("%lld", _max + _max2);
return 0;
}
备注
求树的直径:从任意一点开始DFS,找到最远点pos1,再从pos1开始DFS找到最远点pos2,
pos1和pos2即为树的直径
证明略(易证)
[NOI2003]逃学的小孩 题解的更多相关文章
- BZOJ1509 & 洛谷4408:[NOI2003]逃学的小孩——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=1509 https://www.luogu.org/problemnew/show/P4408 sb ...
- 洛谷 P4408 [NOI2003] 逃学的小孩 题解
Analysis 题意虽然说先去谁家再去谁家,但是我们不需要管这个,因为AA.BB.CC三个点我们可以任意互相交换它们所代表的对象,所以题目要求的就是在一棵树上找到3个点AA.BB.CC令AB+BCA ...
- 【BZOJ1509】[NOI2003]逃学的小孩 直径
[BZOJ1509][NOI2003]逃学的小孩 Description Input 第一行是两个整数N(3 N 200000)和M,分别表示居住点总数和街道总数.以下M行,每行给出一条街道的 ...
- [NOI2003]逃学的小孩(树的直径)
[NOI2003]逃学的小孩 题目描述 Chris家的电话铃响起了,里面传出了Chris的老师焦急的声音:"喂,是Chris的家长吗?你们的孩子又没来上课,不想参加考试了吗?"一听 ...
- BZOJ 1509: [NOI2003]逃学的小孩( 树形dp )
树形dp求出某个点的最长3条链a,b,c(a>=b>=c), 然后以这个点为交点的最优解一定是a+2b+c.好像还有一种做法是求出树的直径然后乱搞... ----------------- ...
- NOI2003 逃学的小孩
这一题不会做啊…… 我觉得真要比赛的话我可能会随机上几万次,然后再用LCA求距离,更新最优值,等到快超时的时候输出答案…… 题解请看2007年陈瑜希论文 代码: ; type node=record ...
- BZOJ1509: [NOI2003]逃学的小孩 (树形DP)
题意:给一棵树 选三个点A,B,C 求A到B的再从B到C的距离最大值 需要满足AB的距离小于AC的距离 题解:首先树上的最大距离就想到了直径 但是被样例误导了TAT BC两点构成了直径 我一开始以为A ...
- [NOI2003]逃学的小孩【观察+树的直径】
Online Judge:Bzoj1509,Luogu P4408 Label:观察,树的直径 题目描述 输入 第一行是两个整数N(\(3≤N≤200000\))和M,分别表示居住点总数和街道总数.以 ...
- P4408 逃学的小孩 题解
题目描述 Chris家的电话铃响起了,里面传出了Chris的老师焦急的声音:"喂,是Chris的家长吗?你们的孩子又没来上课,不想参加考试了吗?"一听说要考试,Chris的父母就心 ...
随机推荐
- jmeter链接数据库操作
jmeter链接数据库操作步骤 首先要先下载mysql-connector-java-5.1.39-bin.jar驱动包 链接:https://pan.baidu.com/s/14F4rp4uH1hX ...
- 【MM系列】SAP OX09中的地址如何取
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:[MM系列]SAP OX09中的地址如何取 ...
- 递归算法之排列组合-求一个集合S的m个元素的组合和所有可能的组合情况
求一个集合S的m个元素组合的所有情况,并打印出来,非常适合采用递归的思路进行求解.因为集合的公式,本身就是递归推导的: C(n,m) = C(n-1,m-1) + C(n-1,m). 根据该公式,每次 ...
- python每日一练:0000题
**第 0000 题:**将你的 QQ 头像(或者微博头像)右上角加上红色的数字,类似于微信未读信息数量那种提示效果. 类似于图中效果 示例代码: from PIL import Image,Imag ...
- Double类型的数值 在写入excel时 如何去掉 科学计算法的 后面数值+ E的 情况
Double start = 20190724100000.000; 写入excel时 是 201907E+13 但想要输出的是 20190724100000 这种格式 Java在java.math包 ...
- express 实现我猜你喜欢功能
工具:利用cookie-parser中间件; 原理: 每次访问某一具体的文章,就表明可能客户端对这类文章感兴趣, 将这类文章的标签添加到cookie里,字段是like; 然后退回到含有 我猜你喜欢模块 ...
- mysql数据库问题———登录进去无法操作显示You must reset your password using ALTER USER statement before executing this statement
linux操作mysql数据库,可以登陆进去,但是操作所有命令都显示You must reset your password using ALTER USER statement before exe ...
- Let's encrypt 通配域名DNS验证方式的证书自动更新
通配符域名不同于一般的单域名证书. 为了解决之前一篇短文中通配域名通过DNS方式验证的证书自动更新问题. 需要使用到第三方域名提供商的API, 用于自动添加域名的TXT记录, 实现自动验证并完成证书更 ...
- 数据分析画图,使用原生sql查询数据
1.使用工具 https://www.hcharts.cn/ http://echarts.baidu.com/ 2.子表查询 id 创建时间 内容 处理者 1 2017-02-01 11:11 1 ...
- Android数据库使用指南(下)
前言 上面已经说了,对表进行修改,其实就是对数据库进行升级,删除表也算升级啊,反正就是发生变化,数据库就需要升级. 所以老实说其实有个地方决定了数据库的版本 public class DBHelper ...