NOI2013 快餐店
总的来说,还是很容易想的,就是有点恶心。
首先,很明显只有一个环。

我们先找出这个环,给各棵树编号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 快餐店的更多相关文章
- 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 [Noi2013]快餐店
Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...
- 3242: [Noi2013]快餐店 - BZOJ
Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...
- 动态规划:NOI2013 快餐店
Description 小 T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近 的地方. 快餐店的顾客分布 ...
- bzoj 3242: [Noi2013]快餐店
Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城 ...
- BZOJ3242/UOJ126 [Noi2013]快餐店
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- CF835F Roads in the Kingdom/UOJ126 NOI2013 快餐店 树的直径
传送门--CF 传送门--UOJ 题目要求基环树删掉环上的一条边得到的树的直径的最小值. 如果直接考虑删哪条边最优似乎不太可做,于是考虑另一种想法:枚举删掉的边并快速地求出当前的直径. 对于环上的点, ...
- 【uoj126】 NOI2013—快餐店
http://uoj.ac/problem/126 (题目链接) 题意 求基环树直径. Solution zz选手迟早退役,唉,右转题解→_→:LCF 细节 拓扑排序的时候度数为0时入队.我在想什么w ...
随机推荐
- Stooge排序
又叫臭皮匠排序... 在<算法导论>作为反例出现的漂亮但极其低效的排序算法. 基本思路是:只要数组长度大于3,先将头与尾排序,然后递归调用排序前三分之二,再递归调用排序后三分之二,最后再递 ...
- 数据库版本管理工具Flyway(4.0.3)---介绍(译文)
Flyway Evolve your Database Schema easily and reliably across all your instances 简单的.可靠的升级(发展)你的数据库模 ...
- 数据库存储过程 — Sql Server
Mysql.Oracle等主流关系型数据库基本都支持存储过程,这里使用Sql Server为例进行说明. 存储过程的概念: Sql Server存储过程 SQL Server 中的存储过程是由一个或多 ...
- Tips:javascript 图片放大和取得尺寸
1)获取图片尺寸 <img src="http://img.my.csdn.net/uploads/201309/03/1378223257_7957.jpg" alt=&q ...
- Append加载动态轮播
前几天遇到了些小麻烦,不过很快就解决了.之所以要记下来是因为作为一名前端的程序员,要理解页面的加载顺序是最重要的.要不然自己写程序意外的出现bug~~ 刚开始写利用Append的时候,利用火狐的fir ...
- AsyncHttpClient 登录 Application Fragment 回调 监听 软键盘
Activity /**登录界面及登陆后用户首页界面,使用两个Fragment实现*/ public class LoginActivity extends Activity implements L ...
- 【反射】Reflect 介绍 示例
介绍 JAVA反射机制是指:在运行状态中,对于任意一个[类],都能够知道这个类的所有属性和方法:对于任意一个[对象],都能够调用它的所有属性和方法:这种[动态]获取类中的信息以及动态调用对象的成员的功 ...
- SqlServer2000下实现行列转换
SqlServer2000下实现行列转换 2011-04-06 22:07:07| 分类: SQL Server | 标签:sqlserver 2000 行列转换 sql |举报|字号 订 ...
- .net打包/c#winfrom程序打包
1:新建安装部署项目 打开VS,点击新建项目,选择:其他项目类型->安装与部署->安装向导(安装项目也一样),然后点击确定.(详细见下图) 此主题相关图片如下: 2:安装向导 关闭后打开安 ...
- JavaScript“闭包”精解
一.变量的作用域 要理解闭包,首先必须理解Javascript特殊的变量作用域. 变量的作用域无非就是两种:全局变量和局部变量. 详细了解 Javascript语言的特殊之处,就在于函数内部可以直接读 ...