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 求树的直径,把树的直 ...
随机推荐
- No.1001_第六次团队会议
黯淡的一日 今天发生了很令人不爽的一件事,杜正远又被叫去实验室了.昨天界面就很难做,而且我们组人手稀缺,他的缺席让我很难做下去. 今天开会我自己没做出什么来,就加了一个群组的添加功能,同样,曾哲昊也没 ...
- bata2
目录 组员情况 组员1(组长):胡绪佩 组员2:胡青元 组员3:庄卉 组员4:家灿 组员5:凯琳 组员6:翟丹丹 组员7:何家伟 组员8:政演 组员9:黄鸿杰 组员10:刘一好 组员11:何宇恒 展示 ...
- 在visual studio中查看源代码
地址:https://docs.microsoft.com/zh-cn/visualstudio/ide/go-to-and-peek-definition?view=vs-2017 在 Visual ...
- express框架实现承载静态页面的能力
我们知道nodejs本身不具有一个web容器的作用,不像tomcat或者IIS这样的服务器一样天然具有web容器承载静态动态页面的能力,如果要原生实现的话需要自己通过路由配置,比较麻烦,而expres ...
- Mscomm控件安装问题 License information for TMSComm not found.
操作步骤: 1.打开delphi,菜单选择compoents->import Activex control,然后选择那个mscomm32.ocx安装即可. 2.注册MScomm控件 开始- ...
- 读书笔记-《Linux/Unix设计思想》
本书主要讲的是Unix程序设计思想,具体涉及到linux的内容不多. 整本书的一个基本出发点是开源.其中主要强调的观点包括: 1.小即是美 作者持有的主要观点是程序应该以小为美.小程序实现小功能,每个 ...
- selenium异常问题汇总(持续更新版)
webdriver启动firefox时如果遇到以下错误,则说明selenium的版本和firefox不兼容了,升级selenium版本就好 org.openqa.selenium.firefox.No ...
- 使用w3m访问页面执行函数
Ubuntu系统中 在计划任务中使用 w3m命令访问地址 locahost/index.php,或许使用curl "locahost/index.php"来访问地址
- java 重写你可以这么理解 因为 方法名和参数类型个数相同 所以这就是重写了 然后 因为是重写 所以 返回值必须相同
java 重写你可以这么理解 因为 方法名和参数类型个数相同 所以这就是重写了 然后 因为是重写 所以 返回值必须相同
- Qt——用于表格QTableView的模型
如果想使用表格来呈现数据,Qt提供了一个方便的部件QTableWidget,但是直接用它实现一些功能可能比较困难.这里将介绍一种强大.灵活的方式来操作表格. 一.模型/视图架构 在这个架构中,模型用于 ...