P1099 树网的核 && P2491 [SDOI2011]消防
给定一棵树, 你可以在树的直径上确定一条长度不超过 \(S\) 的链, 使得树上离此链最长的点距离最小, 输出这个距离
P2491 数据范围为 P1099 的 \(1000\) 倍
Solution
首先两次 \(dfs\) 确定树的直径, 即第一次随意从某一点出发到达最远点记为 \(s\), 第二次从 \(s\) 出发到达最远点 \(t\) , 则 \(s-t\) 即为树的直径
现在我们得到了直径, 试想树上现在有一条链, 包含点 \(a_{1},a_{2}...a_{n}\), 树上到此链最长的点无非是以下三个的最大值:
- \(a_{1}\) 到直径首的长度
- \(a_{t}\) 到直径末的长度
- \(Max_{i = 1}^{t}d_{i}\), \(d_{i}\) 为点 \(i\) 在不经过直径能到达最远点的长度
通过树的性质可得: 链上最远点长度必然包括直径到最远点的长度(才能保证最优)
所以实际上我们只需要维护在直径上长度不超过 \(S\) 的链的 \(1, 2\) 两点, 与直径最长取最大值即可
贪心可得在保证链长 \(<=S\) 的情况下越长越优
所以维护两个指针 \(l, r\), 维护链上的左右端点
枚举每一个右端点同时保持链长 \(<= S\) ,缩短左端点更新答案即可
此题细节较多,看注释
Code(P2491)
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<vector>
#define LL long long
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const int maxn = 600019,INF = 1e9 + 19;
int head[maxn],nume = 1;
struct Node{
int v,dis,nxt;
}E[maxn << 3];
void add(int u,int v,int dis){
E[++nume].nxt = head[u];
E[nume].v = v;
E[nume].dis = dis;
head[u] = nume;
}
int num, S;
int s, t;
int pre[maxn], dis[maxn], disl[maxn], disr[maxn], disnxt[maxn];//前驱点,非路径距离,链上距离,邻接距离
vector<int>G;
bool vis[maxn];
struct Fa{int p, dis;};
Fa get_longest(int u, int F, int tim){//函数多用
Fa ret = (Fa){u, 0};int last = u, dn = 0;
for(int i = head[u];i;i = E[i].nxt){
int v = E[i].v;
if(v == F || vis[v])continue;
Fa ansv = get_longest(v, u, tim);
if(ansv.dis + E[i].dis > ret.dis){
last = v, dn = E[i].dis;
ret.dis = ansv.dis + E[i].dis;
ret.p = ansv.p;
}
}
if(tim == 1)pre[u] = last, disnxt[u] = dn;
return ret;
}
int ans = INF;
struct Que{
int index, val;
}Q[maxn];
int get_min(){
int now = s, add = 0;
while(pre[now] != now){
G.push_back(now);//入链
dis[now] = get_longest(now, -1, 0).dis;//处理非链上最长路径
add = max(add, dis[now]);
now = pre[now];
}
G.push_back(now);
dis[now] = get_longest(now, -1, 0).dis;//处理终点
add = max(add, dis[now]);
int tot = 0;
for(int i = G.size() - 1;i >= 1;i--){
now = G[i];
disr[now] = tot;
tot += disnxt[G[i - 1]];
}
disr[s] = tot;//处理链上最长距离的另一半
int l = 0, r = 0, len = 0;
ans = max(add, disr[G[r]]);
while(r < G.size()){
len += disnxt[G[r]];r++;
while(len > S)len -= disnxt[G[l]], l++;
//printf("l=%d r=%d\n", G[l], G[r]);
now = max(disr[G[r]], disl[G[l]]);
now = max(now, add);
ans = min(ans, now);
}
ans = max(ans, add);
return ans;
}
int main(){
num = RD();S = RD();
for(int i = 1;i <= num - 1;i++){
int u = RD(), v = RD(), dis = RD();
add(u, v, dis), add(v, u, dis);
}
s = get_longest(1, -1, 0).p, t = get_longest(s, -1, 1).p;
int i = s, tot = 0;
while(pre[i] != i)vis[i] = 1, disl[i] = tot, tot += disnxt[i], i = pre[i];//s到t
vis[t] = 1, disl[t] = tot;//标记直径上的点, 处理链上最长路径
printf("%d\n", get_min());
return 0;
//for(int i = 1;i <= num;i++)if(vis[i])printf("dis[%d]=%d\n", i, dis[i]);
}
P1099 树网的核 && P2491 [SDOI2011]消防的更多相关文章
- 洛谷 P1099 树网的核+P2491 [SDOI2011]消防
写在前面:由于是双倍经验就放一块了,虽然数据范围差的有点大. 题目链接 题意:在树的直径上选择一条长度不超过s的路径使这条路径上的点到树上任意点的最大距离最小. 这题数据好像非常水,我写了上界n^2不 ...
- NOIP2007 树网的核 && [BZOJ2282][Sdoi2011]消防
NOIP2007 树网的核 树的直径的最长性是一个很有用的概念,可能对一些题都帮助. 树的直径给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径边权之和.树中最远的两个节点之间 ...
- P2491 消防/P1099 树网的核
P2491 消防/P1099 树网的核 双倍经验,双倍快乐. 题意 在一个树上选择一段总长度不超过\(s\)的链使所有点到该链距离的最大值最小. 输出这个最小的值. 做法 Define:以下\(s\) ...
- 洛谷 P1099 树网的核
P1099 树网的核 题目描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W ...
- bzoj1999 / P1099 树网的核
P1099 树网的核 (bzoj数据加强) 前置知识:树的直径 (并不想贴我的智障写法虽然快1倍但内存占用极大甚至在bzoj上MLE) 正常写法之一:用常规方法找到树的直径,在直径上用尺取法找一遍,再 ...
- P1099 树网的核——模拟+树形结构
P1099 树网的核 无根树,在直径上找到一条长度不超过s的路径,使得最远的点距离这条路径的距离最短: 首先两遍dfs找到直径(第二次找的时候一定要吧father[]清零) 在找到的直径下枚举长度不超 ...
- [洛谷P2491] [SDOI2011]消防
洛谷题目链接:[SDOI2011]消防 题目描述 某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这个国家的人对火焰有超 ...
- [NOIP2007] 提高组 洛谷P1099 树网的核
题目描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并 ...
- 【luogu P2491 [SDOI2011]消防】 题解
题目链接:https://www.luogu.org/problemnew/show/P2491 题外话: OI一共只有三种题--会的题,不会的题,二分题. 题解: step 1 求树的直径,把树的直 ...
随机推荐
- Linux基础入门--04
目录结构及文件基本操作 实验介绍: 1.Linux 的文件组织目录结构. 2.相对路径和绝对路径. 3.对文件的移动.复制.重命名.编辑等操作. 一.Linux 目录结构 在讲 Linux 目录结构之 ...
- 每日scrum(1)
今天又正式开始了第二个冲刺周期,计划十天,主要需要改进的地方包括UI界面,还有一些细节的把握. 今天出现的主要问题有:在讨论UI界面风格的时候,小组内部意见不统一,对UI界面的创作流程不熟悉,以及难度 ...
- iOS 开发学习-import和include的区别
//当我们在代码中使用两次#include的时候会报错:因为#include相当于拷贝头文件中的声明内容,所以会报重复定义的错误 //但是使用两次#import的话,不会报错,所以他可以解决重复导入的 ...
- 自学iOS-获取当前时间
NSDate * senddate=[NSDate date]; NSDateFormatter *dateformatter=[[NSDateFormatter alloc] init]; [dat ...
- 软工实践-Beta 冲刺 (6/7)
队名:起床一起肝活队 组长博客:博客链接 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过去两天完成了哪些任务 描述: 1.界面的修改与完善 展示GitHub当日代码/文档签入记 ...
- BETA随笔6/7
前言 我们居然又冲刺了·六 团队代码管理github 站立会议 队名:PMS 530雨勤(组长) 过去两天完成了哪些任务 新方案代码比之前的更简单,但是对场景的要求相应变高了,已经实现,误差感人 代码 ...
- (小组)第六次作业:NABCD模型分析。产品Backlog。
NABCD模型分析: NABCD模型分析 1.N——need需求 随着时代的进步,人们生活水平的提高,现在手机的普及率已经非常高了,而且现在的家长很多时候会忙于工作,很少会花时间出来给自己读小学的孩子 ...
- JavaBean 与 EJB 的区别
JavaBean在一般情况下指的是实体类,在大部分情况下和POJO是同义词,基本构成就是一些字段和与之对应的 setter.getter方法,如果一个JavaBean需要在不同的JVM的进程中进行传递 ...
- STM32F103 CAN中断发送功能的再次讨论
转自:http://yiyutingmeng.blog.163.com/blog/static/124258578201191584629146/ 我在之前的一篇博客日志中,写过关于CAN发送功能如何 ...
- Beta阶段——4
一.提供当天站立式会议照片一张: 二. 每个人的工作 (有work item 的ID) (1) 昨天已完成的工作: 完善了用户管理模式的功能 (2) 今天计划完成的工作: 对用户功能的添加. (3) ...