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. Java框架学习之Hibernate入门

    Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库. Hibernate可以应用在任何使用JDB ...

  2. java中paint repaint update 之间的关系

    最近总结了一下java中的paint,repaint和updata三者之间的关系,首先咱们都知道用paint方法来绘图,用repaint重绘,用update来写双缓冲.但是他们之间是怎么来调用的呢,咱 ...

  3. android开发常用组件(库)推荐

    版本兼容:官方 support 全家桶 网络请求:Android-Async-Http.Retrofit.OkHttp.Volley图片加载:Glide 和 Universal-Image-Loade ...

  4. Highcharts 带有数据标签曲线图表

    <html> <head> <meta charset="UTF-8" /> <title>Highcharts</title ...

  5. android之字体阴影效果

    今天刚刚好做了个字体阴影的效果,感觉加上了阴影的效果立体感十足啊!写了个简单的demo与大家分享下!主要是以下四个属性 android:shadowColor  阴影的颜色  android:shad ...

  6. android GestureDetector 手势的判断

    import android.app.Activity;import android.os.Bundle;import android.util.Log;import android.view.Ges ...

  7. 酷Q机器人,QQ机器人使用教程

    软件介绍: 酷Q,软件酷Q机器人是一款基于webqq开发的一款自动接收.处理qq消息的软件. 改程序使用易语言编写,精简大量不必要代码,减小了软件体积,优化程序速度,使得酷Q更加轻巧好用. 在消息处理 ...

  8. Java基础知识强化48:Java中哈希码

    1.概念:      哈希其实只是一个概念,没有什么真实的指向.它的目的是保证数据均匀的分布到一定的范围内.所以不同数据产生相同的哈希码是完全可以的.      现在是站在JAVA虚拟机的角度来看内存 ...

  9. jquery获取checkbox被选中的值

    只用一个循环,就可以找出被选中的checkbox的值 var s; $("[name = b]:checkbox").each(function () {              ...

  10. Android material design support library -- CollapsingToolbarLayout简介

    本文是codetrick上material design support library教程的第三篇,主要讲的是CollapsingToolbarLayout的概念和应用方法. 原文链接:Materi ...