P2491 消防

题目描述

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

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

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

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

输入输出格式

输入格式:

输入包含n行:

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

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

输出格式:

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

说明

【数据规模和约定】

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

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

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


对于消防局的建设的地点,选择在树的直径上是最优的。

树的直径:树中的最长简单路

  • 证明:

假设消防局为黄链\(A\)(\(A\)不在\(D\)上),其中有点\(A_1\),\(A_2\)......\(A_n\),树的某一直径为蓝链\(D\),两边的点分别为\(D_1\),\(D_2\)

则对于点\(A_i\)来说,在整颗树中最远的点即为\(D_1\)或\(D_2\)

证明(证明中的证明):

假设存在\(S_2\)使得\(D_3\)距离Ai最远,则必有\(S_2+S_1>S_4\)(或\(S_3\)),即产生了新的直径,不成立,得证。

由以上可知,黄链上的点到外面最远的一个点的距离为

\(Dis=min\{E(A_i,D_1),E(A_i,D_2),i\in[1,n]\}\)

若令\(dis\)最小,则链\(A\)必在链\(D\)上。

但是,当\(A\)在\(D\)上时,链\(A\)到外面的点(即不在直径上的点)的距离\(f\)是可能大于\(dis\)的,是合法的。

这样是否矛盾?

不矛盾,因为任何一个在外面的链\(A\)的\(dis\)都是大于在直径上的链\(A\)的\(f\)的

其实不太严谨哈


那么对于这个题,我们就有了思路啊

  1. 2次dfs求出树的直径(第一次求出某条直径端点,第二次直接抽出直径)

  2. 预处理直径上每个点\(i\)向外延伸的最长距离\(c[i]\)

  3. 对于待检验链\(A\),左端为\(A_i\),右端为\(A_j\),此时的最长距离即为\(max\{E(A_1,A_i),E(A_j,A_n),c[k],k\in[i,j]\}\)

前两个好弄,前缀和就行。

后一个是\(RMQ\)问题,\(ST\)表线段树维护一下就行。

但还有个更优的,我们注意到我们相当于拿一个窗口划过了链\(A\),对啊,妥妥的单调队列维护啊


code:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
using namespace std;
const int N=300010;
int n,s;
int used[N];
struct node1
{
int i,w;
node1(){}
node1(int i,int w)
{
this->i=i;
this->w=w;
}
};
deque <node1> q;
struct node
{
int i,w;
node(){}
node(int i,int w)
{
this->i=i;
this->w=w;
}
};
vector <node > g[N];
int l,m_max=0;
int son[N],ww[N];
int c[N];//节点i外面的最长边
void dfs0(int now,int len)
{
used[now]=true;
if(m_max<len)
{
m_max=len;
l=now;
}
for(int i=0;i<g[now].size();i++)
{
int v=g[now][i].i,w=g[now][i].w;
if(!used[v])
dfs0(v,w+len);
}
} void dfs1(int now)
{
used[now]=true;
for(int i=0;i<g[now].size();i++)
{
int v=g[now][i].i,w=g[now][i].w;
if(!used[v])
{
dfs1(v);
if(ww[v]+w>ww[now])
{
ww[now]=ww[v]+w;
son[now]=v;
}
}
}
} int dfs(int now)
{
int mmax=0;
used[now]=1;
for(int i=0;i<g[now].size();i++)
{
int v=g[now][i].i,w=g[now][i].w;
if(!used[v])
mmax=max(dfs(v)+w,mmax);
}
return mmax;
}
int a[N],f[N]; int main()
{
cin>>n>>s;
int u,v,w;
for(int i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
node tt(v,w);
g[u].push_back(tt);
tt.i=u;
g[v].push_back(tt);
}
memset(used,0,sizeof(used));
dfs0(1,0);//找到左端点
memset(used,0,sizeof(used));
memset(son,0,sizeof(son));
memset(ww,0,sizeof(ww));
dfs1(l);//存储直径
memset(used,0,sizeof(used));
int now=l;
int cnt=0;
while(now)
{
used[now]=1;
a[++cnt]=now;
now=son[now];
}
now=l;
cnt=0;
while(now)
{
c[++cnt]=dfs(now);
now=son[now];
}
for(int i=1;i<=cnt;i++)
f[i]=ww[a[i]];
int ans=0x3f3f3f3f,ll=1;
for(int i=1;i<=cnt;i++)
{
node1 tt(i,c[i]);
while(!q.empty()&&c[i]>q.front().w) q.pop_front();
q.push_front(tt);
while(f[ll]-f[i]>s)
{
ll++;
if(q.back().i<ll)
q.pop_back();
}
ans=min(ans,max(f[1]-f[ll],max(f[i],q.back().w)));
}
cout<<ans<<endl;
return 0;
}

结论:

  • 两遍DFS求树的直径
  • 权有上界的 以最小代价联通整个树的 链在树的直径上

2018.4.27

洛谷 P2491消防 解题报告的更多相关文章

  1. 洛谷 P2058 海港 解题报告

    P2058 海港 题目描述 小K是一个海港的海关工作人员,每天都有许多船只到达海港,船上通常有很多来自不同国家的乘客. 小K对这些到达海港的船只非常感兴趣,他按照时间记录下了到达海港的每一艘船只情况: ...

  2. 洛谷 P3956 棋盘 解题报告

    P3956 棋盘 题目描述 有一个\(m×m\)的棋盘,棋盘上每一个格子可能是红色.黄色或没有任何颜色的.你现在要从棋盘的最左上角走到棋盘的最右下角. 任何一个时刻,你所站在的位置必须是有颜色的(不能 ...

  3. 洛谷 P1979 华容道 解题报告

    P1979 华容道 题目描述 小\(B\)最近迷上了华容道,可是他总是要花很长的时间才能完成一次.于是,他想到用编程来完成华容道:给定一种局面, 华容道是否根本就无法完成,如果能完成, 最少需要多少时 ...

  4. BZOJ 3545 / 洛谷 P4197 Peaks 解题报告

    P4197 Peaks 题目描述 在\(\text{Bytemountains}\)有\(N\)座山峰,每座山峰有他的高度\(h_i\).有些山峰之间有双向道路相连,共\(M\)条路径,每条路径有一个 ...

  5. 虔诚的墓主人(BZOJ1227)(洛谷P2154)解题报告

    题目描述 小W是一片新造公墓的管理人.公墓可以看成一块N×M的矩形,矩形的每个格点,要么种着一棵常青树,要么是一块还没有归属的墓地. 当地的居民都是非常虔诚的基督徒,他们愿意提前为自己找一块合适墓地. ...

  6. 洛谷 P2672 推销员 解题报告

    P2672 推销员 题目描述 阿明是一名推销员,他奉命到螺丝街推销他们公司的产品.螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户.螺丝街一共有N家住户,第i家住户到入口的距离为 ...

  7. 洛谷 P2679 子串 解题报告

    P2679 子串 题目描述 有两个仅包含小写英文字母的字符串\(A\)和\(B\). 现在要从字符串\(A\)中取出\(k\)个互不重叠的非空子串,然后把这\(k\)个子串按照其在字符串\(A\)中出 ...

  8. 洛谷 P1076 寻宝 解题报告

    P1076 寻宝 题目描述 传说很遥远的藏宝楼顶层藏着诱人的宝藏.小明历尽千辛万苦终于找到传说中的这个藏宝楼,藏宝楼的门口竖着一个木板,上面写有几个大字:寻宝说明书.说明书的内容如下: 藏宝楼共有\( ...

  9. 洛谷 P1582 倒水 解题报告

    P1582 倒水 题目描述 一天,CC买了N个容量可以认为是无限大的瓶子,开始时每个瓶子里有1升水.接着~~CC发现瓶子实在太多了,于是他决定保留不超过K个瓶子.每次他选择两个当前含水量相同的瓶子,把 ...

随机推荐

  1. FSMC的个人理解

    个人理解: FSMC相当于外部设备存储器地址在FSMC对应存储地址中的映射,通过在FSMC的存储地址中写数据,就能通过FSMC的地址线和数据线,将地址和数据写到外部设备存储器地址中.所以,程序中,需要 ...

  2. Apache Spark 2.2中基于成本的优化器(CBO)(转载)

    Apache Spark 2.2最近引入了高级的基于成本的优化器框架用于收集并均衡不同的列数据的统计工作 (例如., 基(cardinality).唯一值的数量.空值.最大最小值.平均/最大长度,等等 ...

  3. 【亲测有效】无法定位链接器!请检查 tools\link.ini 中的配置是否正确的解决方案

    在进行易语言静态编译的时候,出现了如下错误: 正在进行名称连接...正在统计需要编译的子程序正在编译...正在生成主程序入口代码程序代码编译成功等待用户输入欲编译到的文件名正在进行名称连接...开始静 ...

  4. RDMA技术解析

    文章出处:https://mp.weixin.qq.com/s/pW-tQR4AYr1Gtd4dpHVW7w 摘要:远程直接内存访问(即Remote Direct Memory Access)是一种直 ...

  5. Spring RPC 入门学习(1)-HelloWorld入门

    Spring搭建RPC环境 第一,下载所需要的jar包,下载地址:https://yunpan.cn/cPErQeANrSMyB (提取码:63e5),见下图: 第二,新建动态WebProject,把 ...

  6. 软件工程M1/M2总结

    也不分M1/M2了,就从头到尾的梳理一下这学期的软工课吧. 第一节课,老师就稀里哗啦说了一下这学期要怎么搞,什么个人项目啦,结对项目啦,团队项目一二啦,还要组队啊什么的,然后风风火火的组队. 个人项目 ...

  7. 《Linux内核设计与实现》 第一二章学习笔记

    <Linux内核设计与实现> 第一二章学习笔记 第一章 Linux内核简介 1.1 Unix的历史 Unix的特点 Unix很简洁,所提供的系统调用都有很明确的设计目的. Unix中一切皆 ...

  8. win10装MySQL5.7

    越来越发现装MySQL很费劲啊,装了N次,都很懵逼,找对的解决方案很重要. Mysql5.7下载地址:http://xiazai.zol.com.cn/detail/4/33431.shtml 安装步 ...

  9. windows、ubuntu、centos7下mysql 的安装与使用

    一.windows 及ubuntu下安装 windows可以傻瓜式安装,另一种空闲了下来写,也不麻烦 ubuntu: apt-get install mysql 强烈推荐使用ubuntu从这儿就很方便 ...

  10. HP 4411s Install Red Hat Enterprise Linux 5.8) Wireless Driver

    pick up from http://blog.163.com/wangkangming2008%40126/blog/static/78277928201131994053617/ # cp iw ...