[BZOJ2282]消防
Description
Input
输入包含n行:
第1行,两个正整数n和s,中间用一个空格隔开。其中n为城市的个数,s为路径长度的上界。设结点编号以此为1,2,……,n。
从第2行到第n行,每行给出3个用空格隔开的正整数,依次表示每一条边的两个端点编号和长度。例如,“2 4 7”表示连接结点2与4的边的长度为7。
Output
输出包含一个非负整数,即所有城市到选择的路径的最大值,当然这个最大值必须是所有方案中最小的。
Sample Input
5 2
1 2 5
2 3 2
2 4 4
2 5 3
【样例输入2】
8 6
1 3 2
2 3 2
3 4 6
4 5 3
4 6 4
4 7 2
7 8 3
Sample Output
5
【样例输出2】
5
HINT
对于100%的数据,n<=300000,边长小等于1000。
Source
首先我们应该想到这条路径一定在树的直径上。这里给出证明:
设直径的长度为d,那么直径外的边长度一定小于等于d/2(否则该路径会与直径的一部分构成一条比直径还长的路径)
若该路径不在直径上,则直径的最远点到该路径的距离至少为d/2
而如果在直径上,一定存在一段路径使得树上所有点的距离到它不超过d/2
所以选在直径上一定是优的,而且在符合题目要求的情况下越长越好。
那么如果我们确定里直径,我们可以O(n)求出直径上每个点到最远点的距离,然后左右指针扫直径,单调队列维护区间最小值即可。
代码:
- #include<iostream>
- #include<cstring>
- #include<cstdio>
- #include<queue>
- using namespace std;
- deque<int>q;
- struct point
- {
- int to;
- int next;
- int dis;
- }e[];
- int n,x,y,z,res=,maxn,s,t,num,ss;
- int d[],head[],f[],pre[];
- bool vis[];
- void add(int from,int to,int dis)
- {
- e[++num].next=head[from];
- e[num].to=to;
- e[num].dis=dis;
- head[from]=num;
- }
- void dfs(int x)
- {
- vis[x]=true;
- for(int i=head[x];i!=;i=e[i].next)
- {
- int to=e[i].to;
- if(!vis[to])
- {
- d[to]=d[x]+e[i].dis;
- dfs(to);
- }
- }
- }
- void dfs1(int x)
- {
- vis[x]=true;
- for(int i=head[x];i!=;i=e[i].next)
- {
- int to=e[i].to;
- if(!vis[to])
- {
- pre[to]=x;
- d[to]=d[x]+e[i].dis;
- dfs1(to);
- }
- }
- }
- void find(int x)
- {
- vis[x]=true;
- for(int i=head[x];i!=;i=e[i].next)
- {
- int to=e[i].to;
- if(!vis[to])
- {
- find(to);
- d[x]=max(d[x],d[to]+e[i].dis);
- }
- }
- }
- void getf()
- {
- int slr=;
- for(int i=t;i!=;i=pre[i])
- {
- f[i]=slr;
- for(int j=head[i];j!=;j=e[j].next)
- {
- int to=e[j].to;
- if(pre[i]==to)
- {
- slr+=e[j].dis;
- break;
- }
- }
- }
- }
- int main()
- {
- scanf("%d%d",&n,&ss);
- for(int i=;i<=n-;i++)
- {
- scanf("%d%d%d",&x,&y,&z);
- add(x,y,z);
- add(y,x,z);
- }
- dfs();
- for(int i=;i<=n;i++)
- {
- if(d[i]>maxn)
- {
- maxn=d[i];
- s=i;
- }
- }
- memset(vis,false,sizeof(vis));
- memset(d,,sizeof(d));
- dfs1(s);
- maxn=;
- for(int i=;i<=n;i++)
- if(d[i]>maxn)
- {
- maxn=d[i];
- t=i;
- }
- memset(vis,false,sizeof(vis));
- memset(d,,sizeof(d));
- for(int i=t;i!=;i=pre[i])
- vis[i]=true;
- for(int i=t;i!=;i=pre[i])
- find(i);
- getf();
- int r=t,l=pre[t];
- q.push_front(l);
- if(d[l]<d[r])
- q.push_back(r);
- while()
- {
- if(pre[l]!=&&f[pre[l]]-f[r]<=ss)
- {
- l=pre[l];
- int ans=max(f[r],maxn-f[l]);
- q.push_front(l);
- while(d[q.back()]<d[l])
- q.pop_back();
- ans=max(ans,d[q.back()]);
- res=min(res,ans);
- }
- else if(l!=r)
- {
- if(q.back()==r)
- q.pop_back();
- r=pre[r];
- int ans=max(f[r],maxn-f[l]);
- ans=max(ans,d[q.back()]);
- res=min(res,ans);
- }
- else if(l==r&&pre[l])
- {
- while(!q.empty())
- q.pop_back();
- l=pre[l];
- r=l;
- q.push_front(l);
- int ans=max(f[r],maxn-f[l]);
- ans=max(ans,d[q.back()]);
- res=min(res,ans);
- }
- else
- break;
- }
- printf("%d",res);
- return ;
- }
这道题综合了许多算法,也有一定的思维难度,是一道不可多得好题
[BZOJ2282]消防的更多相关文章
- [Bzoj2282]消防(二分答案+树的直径)
Description 某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这个国家的人对火焰有超越宇宙的热情,所以这个国家 ...
- 【BZOJ2282】[Sdoi2011]消防 树形DP+双指针法+单调队列
[BZOJ2282][Sdoi2011]消防 Description 某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这 ...
- BZOJ2282 SDOI2011消防/NOIP2007树网的核(二分答案+树形dp)
要求最大值最小容易想到二分答案.首先对每个点求出子树中与其最远的距离是多少,二分答案后就可以标记上一些必须在所选择路径中的点,并且这些点是不应存在祖先关系的.那么如果剩下的点数量>=3,显然该答 ...
- BZOJ1999或洛谷1099&BZOJ2282或洛谷2491 树网的核&[SDOI2011]消防
一道树的直径 树网的核 BZOJ原题链接 树网的核 洛谷原题链接 消防 BZOJ原题链接 消防 洛谷原题链接 一份代码四倍经验,爽 显然要先随便找一条直径,然后直接枚举核的两个端点,对每一次枚举的核遍 ...
- BZOJ2282: [Sdoi2011]消防
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2282 答案一定是在直径上的一段,然后答案一定不会小于不在直径上的点到直径的距离(要是可以的话那 ...
- 【bzoj2282】[Sdoi2011]消防
两次bfs可得直径,答案一定不会小于所有点到直径的距离最大值,只要把直径上的边权设为0,任选直径上一点bfs可得将最大值作为二分下界,二分直径左右端点的舍弃部分 #include<algorit ...
- NOIP2007 树网的核 && [BZOJ2282][Sdoi2011]消防
NOIP2007 树网的核 树的直径的最长性是一个很有用的概念,可能对一些题都帮助. 树的直径给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径边权之和.树中最远的两个节点之间 ...
- bzoj2282
到路径的距离就是到路径上的点最近的距离首先看到最大值最小不难想到二分答案下面的问题就是怎么判断,显然我们是不能穷举路径的我们要找出消防路径的性质仔细研究就会发现消防路径一定是树的直径的一段,这样必然最 ...
- bzoj 2282 [Sdoi2011]消防(树的直径,二分)
Description 某个国家有n个城市,这n个城市中任意两个都连通且有唯一一条路径,每条连通两个城市的道路的长度为zi(zi<=1000). 这个国家的人对火焰有超越宇宙的热情,所以这个国家 ...
随机推荐
- http协议----->http请求方式,post,get
4.http请求方式有七种(http请求是想web资源请求数据) Post get head options delete trace put 常用:GET POST POST例如form表单提交,G ...
- 2017 Multi-University Training Contest - Team 6—HDU6098&&HDU6106&&HDU6103
HDU6098 Inversion 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6098 题目意思:题目很短,给出一个数组,下标从1开始,现在输出一个 ...
- Mac自带Apache和Php
Mac 是默认安装 apache和php,但是需要使用root用户来启用,所以请按照我下面的步骤来: 一.启用root用户1.选取系统偏好设置....2.从显示菜单中,选取“帐户”.3.点按锁图标并使 ...
- arcgis server/portal 日志格式化脚本
友好化格式阅读 背景 通过arcgis for server manager中的logs选项卡可以查看当前站点的日志.其该页面提供了友好的日志显示方式. 但是在实际情况中,如arcgis server ...
- BitCoin Trading Strategies BackTest With PyAlgoTrade
Written by Khang Nguyen Vo, khangvo88@gmail.com, for the RobustTechHouse blog. Khang is a graduate f ...
- (转载)移动Web开发技巧汇总
META相关 1. 添加到主屏后的标题(IOS) <meta name="apple-mobile-web-app-title" content="标题" ...
- IPython的基本功能(转)
原文:http://kochiya.me/www/posts/Ipython!.html 前几天偶然在公司内网上拖了一本 Learning IPython for Interactive Comput ...
- Python中的高级数据结构(转)
add by zhj: Python中的高级数据结构 数据结构 数据结构的概念很好理解,就是用来将数据组织在一起的结构.换句话说,数据结构是用来存储一系列关联数据的东西.在Python中有四种内建的数 ...
- 如何通过 ClickBank 等类似虚拟平台进行在线销售并获得收益
CLICKBANK在国内被广大赚友简称为CB,和淘金小站之前介绍过的PayDotCom一样,都是国外非常著名的CPS广告联盟.CLICKBANK成立于1998年,是全球四个最大的虚拟商品零售平台之一( ...
- PHP计算经纬度之间的距离
<?php /** * 求两个已知经纬度之间的距离,单位为米 * * @param lng1 $ ,lng2 经度 * @param lat1 $ ,lat2 纬度 * @return floa ...