bzoj3242 [Noi2013]快餐店
Description
小T打算在城市C开设一家外送快餐店。送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方。 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两个建筑。任意两个建筑之间至少存在一条由双向道路连接而成的路径。小T的快餐店可以开设在任一建筑中,也可以开设在任意一条道路的某个位置上(该位置与道路两端的建筑的距离不一定是整数)。 现给定城市C的地图(道路分布及其长度),请找出最佳的快餐店选址,输出其与最远的顾客之间的距离。
Input
第一行包含一个整数N,表示城市C中的建筑和道路数目。
接下来N行,每行3个整数,Ai,Bi,Li(1≤i≤N;Li>0),表示一条道路连接了建筑Ai与Bi,其长度为Li 。
Output
仅包含一个实数,四舍五入保留恰好一位小数,表示最佳快餐店选址距离最远用户的距离。
注意:你的结果必须恰好有一位小数,小数位数不正确不得分。
Sample Input
1 4 2
1 3 2
2 4 1
Sample Output
HINT
数据范围
对于 10%的数据,N<=80,Li=1;
对于 30%的数据,N<=600,Li<=100;
对于 60% 的数据,N<=2000,Li<=10^9;
对于 100% 的数据,N<=10^5,Li<=10^9
正解:基环树直径+树形$dp$。
这应该是$NOI2013$最水的一道题吧。。不过我还是写了$3$个小时,因为漏了一个情况,结果还有$95$分。。
很显然,直接求直径是错的,样例$2$就已经告诉你了。那么我们可以发现,这题其实是要求断掉环上一条边的直径,且使得这个直径最小。
我们先在环上随便找一个点作为根,然后$dfs$。先把所有树的情况处理完,这样对于每个点,$f[x]$表示$x$到它子树的最长链,用树形$dp$先搞一下就行了。
然后考虑环上怎么做。枚举断哪条边,然后我们可以记一个前缀最大值和一个后缀最大值。$v1[x]$表示环顶到$x$逆时针,$f[x]+dis(rt,x)$的最大值($rt$即为环顶),$v2[x]$表示环顶到$x$顺时针,$f[x]+dis(rt,x)$的最大值。注意,两个$dis$是不一样的,一个是逆时针的$dis$,另一个是顺时针的。
这样,我们枚举断边,假设我们断掉的是$x->x+1$这条边,那么断这条边的直径就是$f[rt]+max(v1[x],v2[x+1])$和$v1[x]+v2[x+1]$的最大值(注意此时的$f[rt]$可能已经被别的链更新了,所以必须加上)。然后我们对于所有的最大值,取一个最小值即可。
然后这就是我开始的$95$分算法,还有一种情况没有考虑到。。
注意到上面的情况,我们可以发现它算的是环上两点距离和它们子树的最长链,但是这两点是位于断边两侧的,也就是说,断边同侧的两点同样有可能构成直径。
那么如何计算同侧的情况呢?我们设$v1[x]$为环顶到$x$逆时针,$f[x]-dis(rt,x)$的最大值,$v2[x]$为环顶到$x$顺时针,$f[x]-dis(rt,x)$的最大值。那么这时,枚举断边$i->i+1$,答案有可能由$f[x]+dis(rt,x)-v1[x-1]$和$f[x+1]+dis(rt,x+1)-v2[x+2]$的最大值构成,注意到多余部分的$dis$一加一减,正好被抵消了,所以我们是不会算错的。我们算出这两个值以及上面两个值,取一个最大值,再对所有的最大值取一个最小值,就是答案了。
//It is made by wfj_2048~
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define inf (1LL<<60)
#define N (500010)
#define il inline
#define RG register
#define ll long long
#define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace std; struct edge{ int nt,to; ll dis; }g[*N]; int head[N],fa[N],dfn[N],low[N],st[N],n,rt,num,cnt;
ll dis[N],f[N],d[N],v1[N],v2[N],u1[N],u2[N],ans; il int gi(){
RG int x=,q=; RG char ch=getchar();
while ((ch<'' || ch>'') && ch!='-') ch=getchar();
if (ch=='-') q=-,ch=getchar();
while (ch>='' && ch<='') x=x*+ch-,ch=getchar();
return q*x;
} il void insert(RG int from,RG int to,RG ll dis){
g[++num]=(edge){head[from],to,dis},head[from]=num; return;
} il void circle(RG int rt,RG int x,RG ll len){
RG int top=,tp=; RG ll D=len,res=inf,res1,res2;
for (RG int i=x;i!=rt;i=fa[i]) ++tp,D+=dis[i]; top=tp;
for (RG int i=x;i!=rt;i=fa[i]) st[tp--]=i; st[]=rt;
for (RG int i=;i<=top;++i){
d[i]=d[i-]+dis[st[i]];
v1[i]=max(v1[i-],f[st[i]]+d[i]);
u1[i]=max(u1[i-],f[st[i]]-d[i]);
}
for (RG int i=top;i>;--i){
v2[i]=max(v2[i+],f[st[i]]+D-d[i]);
u2[i]=max(u2[i+],f[st[i]]-D+d[i]);
}
for (RG int i=;i<top-;++i){
res1=max(v1[i]+v2[i+],f[rt]+max(v1[i],v2[i+]));
res2=max(f[st[i]]+d[i]+u1[i-],f[st[i+]]+D-d[i+]+u2[i+]);
res=min(res,max(res1,res2));
}
res=min(res,f[rt]+v1[top]),res=min(res,f[rt]+v2[]),ans=max(ans,res); return;
} il void tarjan0(RG int x,RG int p){
fa[x]=p,dfn[x]=low[x]=++cnt; RG int v;
for (RG int i=head[x];i;i=g[i].nt){
v=g[i].to; if (v==p) continue;
if (!dfn[v]){
dis[v]=g[i].dis,tarjan0(v,x);
low[x]=min(low[x],low[v]);
} else low[x]=min(low[x],dfn[v]);
}
for (RG int i=head[x];i;i=g[i].nt){
v=g[i].to; if (v==p) continue;
if (fa[v]!=x && dfn[x]<dfn[v]) rt=x;
}
return;
} il void tarjan(RG int x,RG int p){
fa[x]=p,dfn[x]=low[x]=++cnt; RG int v;
for (RG int i=head[x];i;i=g[i].nt){
v=g[i].to; if (v==p) continue;
if (!dfn[v]){
dis[v]=g[i].dis,tarjan(v,x);
low[x]=min(low[x],low[v]);
} else low[x]=min(low[x],dfn[v]);
if (dfn[x]<low[v]){
ans=max(ans,f[x]+f[v]+g[i].dis);
f[x]=max(f[x],f[v]+g[i].dis);
}
}
for (RG int i=head[x];i;i=g[i].nt){
v=g[i].to; if (v==p) continue;
if (fa[v]!=x && dfn[x]<dfn[v]) circle(x,v,g[i].dis);
}
return;
} il void work(){
n=gi();
for (RG int i=,u,v,w;i<=n;++i) u=gi(),v=gi(),w=gi(),insert(u,v,w),insert(v,u,w);
tarjan0(,); for (RG int i=;i<=n;++i) dfn[i]=low[i]=fa[i]=dis[i]=;
cnt=,tarjan(rt,); printf("%0.1Lf",0.5*(long double)ans); return;
} int main(){
File("foodshop");
work();
return ;
}
bzoj3242 [Noi2013]快餐店的更多相关文章
- BZOJ3242 [Noi2013]快餐店 【环套树 + 单调队列dp】
题目链接 BZOJ3242 题解 题意很清楚,找一点使得最远点最近 如果是一棵树,就是直径中点 现在套上了一个环,我们把环单独拿出来 先求出环上每个点外向树直径更新答案,并同时求出环上每个点外向的最远 ...
- bzoj 3242: [Noi2013]快餐店 章鱼图
3242: [Noi2013]快餐店 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 266 Solved: 140[Submit][Status] ...
- P1399 [NOI2013] 快餐店 方法记录
原题题面P1399 [NOI2013] 快餐店 题目描述 小 T 打算在城市 C 开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小 T 希望快餐店的地址选在离最 ...
- BZOJ3242/UOJ126 [Noi2013]快餐店
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- 3242: [Noi2013]快餐店 - BZOJ
Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...
- 动态规划:NOI2013 快餐店
Description 小 T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近 的地方. 快餐店的顾客分布 ...
- NOI2013 快餐店
http://uoj.ac/problem/126 总的来说,还是很容易想的,就是有点恶心. 首先,很明显只有一个环. 我们先找出这个环,给各棵树编号id[i],然后各棵树分别以环上的点为根,求出每个 ...
- bzoj 3242: [Noi2013]快餐店
Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...
- CF835F Roads in the Kingdom/UOJ126 NOI2013 快餐店 树的直径
传送门--CF 传送门--UOJ 题目要求基环树删掉环上的一条边得到的树的直径的最小值. 如果直接考虑删哪条边最优似乎不太可做,于是考虑另一种想法:枚举删掉的边并快速地求出当前的直径. 对于环上的点, ...
随机推荐
- vue -- 使用sass并引入公共sass文件
sass可以提高我们的开发效率,怎么在vue的项目中使用sass并且可以设置一些公共的文件呢? 使用sass 1.安装sass的依赖包 npm install --save-dev sass-load ...
- 《OD学spark》20160924scala基础
拓展: Hadoop 3.0 NameNode HA NameNode是Active NameNode是Standby可以有多个 HBase Cluster 单节点故障? HBaster -> ...
- 关于SqlDataReader使用的一点疑惑
C#中的SqlDataReader类(System.Data.SqlClient)是用来在保持打开数据库连接的状态下取数据用的 用法如下图: “保持与数据库的连接”这个特性也是SqlDataReade ...
- pyMongo 一些基本操作
1. find() 函数, 可以在函数体内直接指定 filter, sort, projection(限制field), 语法如下: datas = col.find( filter = {" ...
- P1168 中位数(对顶堆)
题意:维护一个序列,两种操作 1.插入一个数 2.输出中位数(若长度为偶数,输出中间两个较小的那个) 对顶堆 维护一个小根堆,一个大根堆,大根堆存1--mid,小根堆存mid+1---n 这样堆顶必有 ...
- 20165224 陆艺杰 Exp 8 Web基础
.基础问题回答 (1)什么是表单 html的一个控件 表单在网页中主要负责数据采集功能 (2)浏览器可以解析运行什么语言 html xml jsp php python 等 (3)WebServer支 ...
- CF213E Two Permutations 线段树维护哈希值
当初竟然看成子串了$qwq$,不过老师的$ppt$也错了$qwq$ 由于子序列一定是的排列,所以考虑插入$1$到$m$到$n-m+1$到$n$; 如何判断呢?可以用哈希$qwq$: 我们用线段树维护哈 ...
- 使用open live writer客户端写博客(亲测有效)
博客都开了这么久了,才开始将资料上传,但是每次都要登录网页确实很麻烦,所以就用open live writer,使用起来真的是挺方便的,所以将我在安装配置时,发现的问题汇总起来以便日后再次碰到忘记怎么 ...
- properties文件 , properties类, 的作用
"properties文件",是java所支持的配置文件类型.java中的properties文件是一种配置文件,主要用于表达配置信息,文件类型为*.properties,格式为文 ...
- JAVA 集合类小结
一 集合和数组 因为本人也是个go的爱好者,所以对于集合类算是摸的比较透的. 说到集合,必须了解数组和集合. Java的数组长度固定,集合长度不定.集合是特定的数据结构的集合. 而go里面并没有集合, ...