消防

题目描述

某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000)。

这个国家的人对火焰有超越宇宙的热情,所以这个国家最兴旺的行业是消防业。由于政府对国民的热情忍无可忍(大量的消防经费开销)可是却又无可奈何(总统竞选的国民支持率),所以只能想尽方法提高消防能力。

现在这个国家的经费足以在一条边长度和不超过s的路径(两端都是城市)上建立消防枢纽,为了尽量提高枢纽的利用率,要求其他所有城市到这条路径的距离的最大值最小。

你受命监管这个项目,你当然需要知道应该把枢纽建立在什么位置上。

输入输出格式

输入格式:

输入包含n行:

第1行,两个正整数n和s,中间用一个空格隔开。其中n为城市的个数,s为路径长度的上界。设结点编号以此为1,2,……,n。

从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。

输出格式:

输出包含一个非负整数,即所有城市到选择的路径的最大值,当然这个最大值必须是所有方案中最小的。

输入输出样例

输入样例#1:

5 2
1 2 5
2 3 2
2 4 4
2 5 3

输出样例#1:

5

输入样例#2:

8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3

输出样例#2:

5

说明

【数据规模和约定】

对于20%的数据,n<=300。

对于50%的数据,n<=3000。

对于100%的数据,n<=300000,边长小等于1000。

题解

这道题可以说是NOIP2007树网的核的数据加强版

那道题由于数据范围极小,所以\(O(n^3),O(n^2),O(nlogsum),O(n)\)都可以过

而这道题就只能后面两种做法了

但是无论如何,首先这道题需要会求树的直径,如果不会的在这里再贴一下代码+一点点注释

  • 两遍dfs/bfs

Code

void dfs(int u,int fa) {
for(int i=head[u]i;i=e[i].next)
{
int to=e[i].to;
if(to!=fa) dis[to]=dis[u]+e[i],v,dfs(to,u)
}
}
int main()
{
//建边
int s=0,t=0;
dfs(1,0);
for(int i=1;i<=n;i++) if(!s || dis[i]>dis[s]) s=i;
memset(dis,0,sizeof(dis)); dfs(s,0);
for(int i=1;i<=n;i++) if(!t || dis[i]>dis[t]) t=i;
//原理:树的直径是树上最长的一条链,因此任取树上一个点,离它最远的点必然是树的直径上的一个端点,找到这个端点后再以它为根,找到离它最远的点,则必然是直径的另一个端点
}
  • 树形dp

    定义dp[i]为以i为根的子树的直径

Code

void DP(int u,int fa) {
for(int i=head[u];i;i=e[i].next) {
int to=e[i].to;
DP(to,u);
ans=max(ans,dp[u]+dp[to]+e[i].v);//此时dp[u]并不包括to这个儿子,
dp[u]=max(dp[u],dp[to]+e[i].v);
}//想一下吧,挺简单的
}

\(O(n^3)\)只要会求树的直径就直接枚举即可

\(O(n^2)\)就是枚举+贪心,在s的范围内,显然越远越好,那么我们确定一段,就可以确定另一段,这样就变成了\(O(n^2)\)

那么再这里就讲一下\(O(nlogsum)\)和\(O(n)\)的做法

\(O(nlogsum)\)

sum为树的总权值

我们依然定义偏心距为其他点到所选路径的最大值

容易发现,此题答案具有单调性,可以二分答案,那么问题就为

求一条路径,使得它的偏心距不超过二分值mid

怎么check?

设直径的两个端点u,v.在直径上找到与u的距离不超过mid的前提下,距离u最远的节点,作为p.同样找到一个距离v不超过mid的最远的节点q

根据直径的最长性,任何其他在u,p之间分叉的子树上的节点与p的距离都不会比与u的距离更远,因此,p,q就是尽量靠近树的中心的节点

我们需要判断p,q之间的距离是否超过s,除此之外还要判断它们之间的距离以及离这条路径最远的点的距离是否超过mid,如果都满足,这就是一个合法解,继续二分

\(O(n)\)

我们可以用一个单调队列来维护答案

依然先求出直径的两个端点

设直径上的点为\(u_1,u_2...u_t\),先把这几个节点标记为已访问,然后通过dfs,求出d[\(u_i\)],表示从\(u_i\)出发,不经过直径上的节点能够到达的最远距离

那么以\(u_i,u_j\)为端点的这条路径的偏心距就是:

\[max(d[u_k](i<=k<=j),max(dist[u_1,u_i],dist[u_j,u_t]))
\]

这个时候用单调队列维护就可以做到\(O(n)\)的了

#include<bits/stdc++.h>
#define Max(a,b) (a)>(b)?(a):(b)
#define Min(a,b) (a)<(b)?(a):(b)
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
inline int read(int &ans) {
ans=0;int f=1;char i=getchar();
while(i<'0' || i>'9') {if(i=='-') f=-1;i=getchar();}
while(i>='0' && i<='9') {ans=(ans<<1)+(ans<<3)+i-'0';i=getchar();}
return ans*f;
}
const int N=500010;
struct edge {
int to,v,next;
}e[2*N];
int n,m,L,cnt,ml,mr,s,ans=2147483647,he,ta;
int head[N],vis[N],dis[N],fa[N];
int q[N],pos[N],f[N];
inline void add(int a,int b,int c) {
e[++cnt].to=b;
e[cnt].v=c;
e[cnt].next=head[a];
head[a]=cnt;
}
void dfs(int u) {
for(int i=head[u];i;i=e[i].next) {
int to=e[i].to;
if(to!=fa[u]) fa[to]=u,dis[to]=dis[u]+e[i].v,dfs(to);
}
}
void find(int u) {
f[u]=dis[u];
for(int i=head[u];i;i=e[i].next)
if(!vis[e[i].to] && e[i].to!=fa[u])
find(e[i].to),f[u]=Max(f[u],f[e[i].to]);
}
int main()
{
int u,v,z;read(n);read(s);
For(i,1,n-1) read(u),read(v),read(z),add(u,v,z),add(v,u,z);
dfs(1);For(i,1,n) if(!mr||dis[i]>dis[mr]) mr=i;
memset(dis,0,sizeof(dis)); fa[mr]=0,dfs(mr);
For(i,1,n) if(!ml||dis[i]>dis[ml]) ml=i;
int l=ml,r=ml; while(l) vis[l]=1,l=fa[l]; l=ml;
while(l) {
while(dis[r]-dis[l]>s) r=fa[r];
find(l); f[l]-=dis[l];
while(he<=ta && pos[he]-dis[l]>s) he++;
while(he<=ta && f[l]>q[ta]) ta--;
q[++ta]=f[l],pos[ta]=dis[l];
ans=Min(ans,Max(q[he],Max(dis[l]-dis[mr],dis[ml]-dis[r])));
l=fa[l];
}
printf("%d\n",ans);
}

博主蒟蒻,随意转载.但必须附上原文链接

http://www.cnblogs.com/real-l/

最新文章

  1. 深入理解javascript选择器API系列第三篇——h5新增的3种selector方法
  2. 烂泥:阿里云RDS本地恢复数据
  3. jsdoc文档
  4. 51nod1258 序列求和V4
  5. 【转】C++:在程序中获取全球唯一标识号(GUID或UUID)
  6. fiddler了解
  7. windows Vista-Server 2016系列激活脚本.cmd
  8. PE文件解析器的编写(二)——PE文件头的解析
  9. How to Find the Self Service Related File Location and Versions
  10. “万能数据库查询分析器” 5.03发布,访问EXCEL将自动为表名前后加上中括弧
  11. Adobe系列产品卸载不干净怎么解决
  12. 自制stm32板子无法烧录程序的问题
  13. 分享Winform datagridview 动态生成中文HeaderText
  14. 解决bootstrap 模态框 数据清除 验证清空
  15. Duplicate Manager Pro for Mac(重复文件查找工具)破解版安装
  16. GridLayout和GridView的区别
  17. 10分钟轻松设置出 A+ 评分的 HTTP/2 网站
  18. ajax代码示例
  19. 特效effects(二)
  20. centos LB负载均衡集群 三种模式区别 LVS/NAT 配置 LVS/DR 配置 LVS/DR + keepalived配置 nginx ip_hash 实现长连接 LVS是四层LB 注意down掉网卡的方法 nginx效率没有LVS高 ipvsadm命令集 测试LVS方法 第三十三节课

热门文章

  1. 抽象类实验:SIM卡抽象
  2. PAT-B java实现
  3. 【Java】Spring MVC 扩展和SSM框架整合
  4. Delphi中客户端获取数据库更新信息(更新条数)
  5. 25、react入门教程
  6. Page Object 设计模式介绍
  7. 深挖 NGUI 基础 之UICamera (二)
  8. KVM WEB管理工具——WebVirtMgr(二)日常配置
  9. Tensorflow Serving介绍及部署安装
  10. deeplearning.ai课程学习(4)