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 求树的直径,把树的直 ...
随机推荐
- PSP Daily新增功能说明书
1.选择输入类别时可以记录原来的输入,支持用户选择记录清空功能 2.添加“恢复最近”button,点击这个按钮可以跳出一个页面显示最近的excel记录,用户可以通过勾选相应的excel文件名,恢复选中 ...
- Java 面试-- 1
JAVA面试精选[Java基础第一部分] 这个系列面试题主要目的是帮助你拿轻松到offer,同时还能开个好价钱.只要能够搞明白这个系列的绝大多数题目,在面试过程中,你就能轻轻松松的把面试官给忽悠了 ...
- A Survey on the Security of Stateful SDN Data Planes
论文摘要: 本文为读者提供新兴的SDN带状态数据平面,集中关注SDN数据平面编程性带来的隐患. I部分 介绍 A.带状态SDN数据平面的兴起 B.带状态数据平面带来的安全隐患 引出带状态数据平面的安全 ...
- POJ 2096 Collecting Bugs 期望dp
题目链接: http://poj.org/problem?id=2096 Collecting Bugs Time Limit: 10000MSMemory Limit: 64000K 问题描述 Iv ...
- 【区间DP】codevs3657 括号序列题解
题目描述 Description 我们用以下规则定义一个合法的括号序列: (1)空序列是合法的 (2)假如S是一个合法的序列,则 (S) 和[S]都是合法的 (3)假如A 和 B 都是合法的,那么AB ...
- 消息队列第二篇:MessageQueue实战(课程订单)
上一篇:消息队列介绍 本篇一开始就上代码,主要演练MessageQueue的实际应用.用户提交订单(消息发送),系统将订单发送到订单队列(Order Queue)中:订单管理系统(消息接收)端,监听消 ...
- ASP.NET MVC 5.0 参考源码索引
http://www.projky.com/asp.netmvc/5.0/Microsoft/AspNet/Mvc/Facebook/FacebookAppSettingKeys.cs.htmlhtt ...
- 软工网络15团队作业8——Beta阶段敏捷冲刺(Day6)
提供当天站立式会议照片一张 每个人的工作 1.讨论项目每个成员的昨天进展 赵铭: 数据库整理. 吴慧婷:我的世界界面完成部分. 陈敏: 我的世界功能--学习情况功能完成. 吴雅娟:我的世界功能--学习 ...
- PAT 1147 Heaps
https://pintia.cn/problem-sets/994805342720868352/problems/994805342821531648 In computer science, a ...
- request使用代理
# *_*coding:utf-8 *_* import requests url = 'http://test.yeves.cn/test_header.php' params = {'id':'1 ...