http://uoj.ac/problem/126

总的来说,还是很容易想的,就是有点恶心。

首先,很明显只有一个环。

我们先找出这个环,给各棵树编号id[i],然后各棵树分别以环上的点为根,求出每个点的深度dep[i],根节点st[i],最深的孩子的深度furthestson[i]和不进入子树最远的点距离f[i],这些都比较好求。

我们分2种情况讨论:

(1)快餐店在环上

将环上的点以furthestson[i]为权值,等价于快餐店到点的最短距离再加上点的权值的最大值最小。

其实我们可以将这个环看成一个正圆,过快餐店的一条直径将这个圆分成2部分,快餐店顺时针到左边的点,逆时针到右边的点,我们分别将左边的点和右边的点分别放在2个单调队列中。

当我们逆时针旋转这条直径的时候,左右两边是单调的,可以用单调队列,然后更新答案即可。

(2)快餐店在树上

我们在(1)中顺便记录一下第i棵树不进入本树可以到达的最远距离h[i]

我们枚举树边(u,v),不失一般性,dep[u]<dep[v],且其长度为l。

那么这条路径v那一端最远可以到的距离为furthestson[v],u那一端最远可以到的距离为max(f[v]-l,dep[u]+h[id[st[u]]])。

然后更新答案即可。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj using namespace std; typedef long long LL;
typedef double DB;
typedef pair<int,int> PII;
typedef complex<DB> CP; #define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define re(i,a,b) for(i=a;i<=b;i++)
#define red(i,a,b) for(i=a;i>=b;i--)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define SF scanf
#define PF printf
#define two(k) (1<<(k)) template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;} const DB EPS=1e-;
inline int sgn(DB x){if(abs(x)<EPS)return ;return(x>)?:-;}
const DB Pi=acos(-1.0); inline void clear(vector<int> *A,int a,int b){int i,j;A->clear();re(i,,a)re(j,,b)A[i].push_back();} inline int gint()
{
int res=;bool neg=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){neg=;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return (neg)?-res:res;
}
inline LL gll()
{
LL res=;bool neg=;char z;
for(z=getchar();z!=EOF && z!='-' && !isdigit(z);z=getchar());
if(z==EOF)return ;
if(z=='-'){neg=;z=getchar();}
for(;z!=EOF && isdigit(z);res=res*+z-'',z=getchar());
return (neg)?-res:res;
} const int maxN=; int N;
int now,first[maxN+];
struct Tedge{int u,v,next,dis;}edge[*maxN+];
DB ans; inline void addedge(int u,int v,int dis)
{
now++;
edge[now].u=u;
edge[now].v=v;
edge[now].dis=dis;
edge[now].next=first[u];
first[u]=now;
} #define next(i) (i%cnt+1)
#define qian(i) ((i-2+cnt)%cnt+1)
int cnt,root[maxN+];
LL lon[maxN+];
int id[maxN+]; int vis[maxN+];
int fa[maxN+];
int sta[maxN+],last[maxN+],top;
inline void DFS()
{
mmst(vis,);
mmst(fa,);
vis[sta[top=]=]=;
last[]=first[];
while(top>=)
{
int u=sta[top],i=last[top],v;
for(v=edge[i].v;i!=-;i=edge[i].next,v=edge[i].v)
{
if(!vis[v])
{
last[top]=edge[i].next;
vis[sta[++top]=v]=;
last[top]=first[v];
fa[v]=u;
break;
}
if(vis[v] && v!=fa[u])
{
while(sta[top]!=v)root[++cnt]=sta[top--];
root[++cnt]=v;
return;
}
}
if(i==-)top--;
}
} inline void findround()
{
int i,j;
DFS();
re(i,,cnt)
{
id[root[i]]=i;
int v,dis;
for(j=first[root[i]],v=edge[j].v,dis=edge[j].dis;j!=-;j=edge[j].next,v=edge[j].v,dis=edge[j].dis)
if(v==root[next(i)]){lon[i]=LL(dis);break;}
}
} int head,tail,que[maxN+]; LL dep[maxN+],furthestson[maxN+],f[maxN+];
int st[maxN+];
inline void solve1(int rt)
{
int i,j;
vis[que[head=tail=]=rt]=;
dep[rt]=;
fa[rt]=;
while(head<=tail)
{
int u=que[head++],v,dis;
for(i=first[u],v=edge[i].v,dis=edge[i].dis;i!=-;i=edge[i].next,v=edge[i].v,dis=edge[i].dis)
if(id[v]== && !vis[v])
{
fa[v]=u;
vis[que[++tail]=v]=;
dep[v]=dep[u]+LL(dis);
}
}
red(j,tail,)
{
int u=que[j],v,dis;
furthestson[u]=;
for(i=first[u],v=edge[i].v,dis=edge[i].dis;i!=-;i=edge[i].next,v=edge[i].v,dis=edge[i].dis)
if(id[v]== && v!=fa[u])
upmax(furthestson[u],furthestson[v]+LL(dis));
}
f[rt]=;
re(j,,tail)
{
int u=que[j],v,dis;LL maxv1=,maxv2=;int hea=-;
for(i=first[u],v=edge[i].v,dis=edge[i].dis;i!=-;i=edge[i].next,v=edge[i].v,dis=edge[i].dis)
if(id[v]== && v!=fa[u])
{
if(furthestson[v]+LL(dis)>maxv1)
maxv2=maxv1,maxv1=furthestson[v]+LL(dis),hea=v;
else
if(furthestson[v]+LL(dis)>maxv2)
maxv2=furthestson[v]+LL(dis);
}
for(i=first[u],v=edge[i].v,dis=edge[i].dis;i!=-;i=edge[i].next,v=edge[i].v,dis=edge[i].dis)
if(id[v]== && v!=fa[u])
{
if(v!=hea)
f[v]=LL(dis)+max(f[u],maxv1);
else
f[v]=LL(dis)+max(f[u],maxv2);
}
}
re(i,,tail)st[que[i]]=rt;
} DB h[maxN+]; struct Tque
{
int head,tail;
DB add,que[*maxN+],idx[*maxN+];////////////////注意,要2倍空间!!!!!!!!!!!!!!!!!!!!
inline void clear(){head=;tail=;add=0.0;}
inline void insert(int id,DB v)
{
++tail;que[tail]=v-add;idx[tail]=id;
while(tail-head+>= && que[tail]>que[tail-])que[tail-]=que[tail],idx[tail-]=idx[tail],tail--;
}
inline void erase(int id){if(idx[head]==id)head++;}
inline DB maxv(){return tail-head+>=?que[head]+add:0.0;}
}Q1,Q2; DB cir,pos[maxN+]; inline DB dist(DB p1,DB p2){return p2>=p1 ? p2-p1 : cir+p2-p1; } inline void move(DB &w,DB l){w+=l;if(w>=cir) w-=cir;} inline void solve2()
{
int i,p1,p2;
DB w1,w2;
cir=0.0;re(i,,cnt)pos[i]=cir,cir+=DB(lon[i]);
p1=;
for(p2=;pos[p2]<=cir/2.0 && p2!=cnt;p2=next(p2));
if(p2==cnt && pos[p2]<=cir/2.0)p2=next(p2);
Q1.clear();Q2.clear();
re(i,p1,qian(p2))Q1.insert(i,DB(furthestson[root[i]])+pos[i]);
if(p2!=p1) re(i,p2,qian(p1))Q2.insert(i,DB(furthestson[root[i]])+cir-pos[i]);
w1=0.0;w2=cir/2.0; mmst(vis,);
vis[]=;
while(vis[]<)
if(dist(w2,pos[p2])<=dist(w1,pos[p1]))
{
DB l=dist(w2,pos[p2]);
Q1.add-=l;
DB v1=Q1.maxv(),v2=Q2.maxv();
upmin(ans,max(v1,v2+l));
upmin(ans,max(v2,v1+l));
if(v1<=(v1+l+v2)/2.0 && (v1+l+v2)/2.0<=v1+l) upmin(ans,(v1+l+v2)/2.0);
Q2.erase(p2);
Q2.add+=l;
move(w1,l);
move(w2,l);
Q1.insert(p2,DB(furthestson[root[p2]])+dist(w1,pos[p2]));
p2=next(p2);
}
else
{
DB l=dist(w1,pos[p1]);
Q1.add-=l;
DB v1=Q1.maxv(),v2=Q2.maxv();
upmin(ans,max(v1,v2+l));
upmin(ans,max(v2,v1+l));
if(v1<=(v1+l+v2)/2.0 && (v1+l+v2)/2.0<=v1+l) upmin(ans,(v1+l+v2)/2.0);
Q1.erase(p1);
Q2.add+=l;
move(w1,l);
move(w2,l);
h[p1]=max(Q1.maxv(),Q2.maxv());
Q2.insert(p1,DB(furthestson[root[p1]])+dist(pos[p1],w1));
p1=next(p1);
vis[p1]++;
}
} inline void solve3()
{
int i;
re(i,,now)
{
int u=edge[i].u,v=edge[i].v;DB l=DB(edge[i].dis);
if(id[u]!= && id[v]!=)continue;
if(dep[u]>dep[v]) swap(u,v);
DB v1=DB(furthestson[v]),v2=max(DB(f[v])-l,DB(dep[u])+h[id[st[u]]]);
upmin(ans,max(v1,v2+l));
upmin(ans,max(v2,v1+l)); if(v1<=(v1+l+v2)/2.0 && (v1+l+v2)/2.0<=v1+l) upmin(ans,(v1+l+v2)/2.0);
}
} int main()
{
/*freopen("foodshop.in","r",stdin);
freopen("foodshop.out","w",stdout);*/
int i;
N=gint();
now=-;mmst(first,-);
re(i,,N)
{
int u=gint(),v=gint(),dis=gint();
addedge(u,v,dis);
addedge(v,u,dis);
}
findround();
mmst(vis,);
re(i,,cnt)solve1(root[i]);
ans=1e60;
solve2();
solve3();
PF("%0.1lf\n",ans);
return ;
}

NOI2013 快餐店的更多相关文章

  1. bzoj 3242: [Noi2013]快餐店 章鱼图

    3242: [Noi2013]快餐店 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 266  Solved: 140[Submit][Status] ...

  2. P1399 [NOI2013] 快餐店 方法记录

    原题题面P1399 [NOI2013] 快餐店 题目描述 小 T 打算在城市 C 开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小 T 希望快餐店的地址选在离最 ...

  3. bzoj3242 [Noi2013]快餐店

    Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...

  4. 3242: [Noi2013]快餐店 - BZOJ

    Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...

  5. 动态规划:NOI2013 快餐店

    Description 小 T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近 的地方. 快餐店的顾客分布 ...

  6. bzoj 3242: [Noi2013]快餐店

    Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...

  7. BZOJ3242/UOJ126 [Noi2013]快餐店

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  8. CF835F Roads in the Kingdom/UOJ126 NOI2013 快餐店 树的直径

    传送门--CF 传送门--UOJ 题目要求基环树删掉环上的一条边得到的树的直径的最小值. 如果直接考虑删哪条边最优似乎不太可做,于是考虑另一种想法:枚举删掉的边并快速地求出当前的直径. 对于环上的点, ...

  9. 【uoj126】 NOI2013—快餐店

    http://uoj.ac/problem/126 (题目链接) 题意 求基环树直径. Solution zz选手迟早退役,唉,右转题解→_→:LCF 细节 拓扑排序的时候度数为0时入队.我在想什么w ...

随机推荐

  1. hadoop 环境搭建

    Hadoop 2.配置HDFS HA (高可用)   前提条件 先搭建 http://www.cnblogs.com/raphael5200/p/5152004.html 的环境,然后在其基础上进行修 ...

  2. Java[4] Jetty工作原理介绍(转)

    转自:https://www.ibm.com/developerworks/cn/java/j-lo-jetty/ Jetty 的工作原理以及与 Tomcat 的比较 Jetty 应该是目前最活跃也是 ...

  3. JavaScript新手学习笔记3——三种排序方式(冒泡排序、插入排序、快速排序)

    每种编程语言学到数组的时候,都会讲到排序算法,当时学C语言的时候,卡在排序算法.今天来总结一下javascript中如何实现三种排序算法. 1.冒泡排序(默认升序排列哦) 原理: 冒泡排序的原理,顾名 ...

  4. 【MongoDB数据库】怎样安装、配置MongoDB

    本blog以最简洁的方式记录了博主在折腾MongoDB过程中点点滴滴,当中包含下载MongoDB.配置环境变量.怎样启动MongoDBserver.怎样连接MongoDBserver以及怎样连接Mon ...

  5. [编辑中] 免费的Internet流量发生器 | Free Internet Traffic Generators

    流量发生器 (Traffic Generator) 是用来检测网络性能,进行网络相关研究的一个很重要的工具.大家可能用过Iperf或者IxChariot,前者是类UNIX环境下的一个免费.开源的网络性 ...

  6. IE标签a嵌套table标签,链接点击无效

    在IE中,使用如下代码将无法触发跳转: <a href="http://xx.xx.com"> <table> <tr> <td>点 ...

  7. iOS开发中的MVC设计模式

    我们今天谈谈cocoa程序设计中的 模型-视图-控制器(MVC)范型.我们将从两大方面来讨论MVC: 什么是MVC? M.V.C之间的交流方式是什么样子的? 理解了MVC的概念,对cocoa程序开发是 ...

  8. 设置Chrome和IE搜索栏的默认搜索引擎

    由于本人比较喜欢用Google香港作为自己的默认搜索引擎,Chrome里面可以轻松设置. ======================== Chrome ======================= ...

  9. 关于PagedDataSource,非常好用的一个分页属性!

    Asp.net提供了三个功能强大的列表控件:DataGrid.DataList和Repeater控件,但其中只有DataGrid控件提供分页功能.相对DataGrid,DataList和Repeate ...

  10. 导出数据库中所有数据到Excle中

    Workbook wb = new HSSFWorkbook();//创建工作簿 Connection conn = DataSourceUtils.getDataSource().getConnec ...