[NOI2013]快餐店

Posted 蒟蒻ZJO :-)

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[NOI2013]快餐店相关的知识,希望对你有一定的参考价值。

题目描述

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

快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两个建筑。任意两个建筑之间至少存在一条由双向道路连接而成的路径。小T的快餐店可以开设在任一建筑中,也可以开设在任意一条道路的某个位置上(该位置与道路两端的建筑的距离不一定是整数)。

现给定城市C的地图(道路分布及其长度),请找出最佳的快餐店选址,输出其与最远的顾客之间的距离。

输入输出格式

输入格式:

 

输入文件foodshop.in第一行包含一个整数N,表示城市C中的建筑和道路数目。

接下来N行,每行3个整数,Ai,Bi,Li(1≤i≤N;Li>0),表示一条道路连接了建筑Ai与Bi,其长度为Li 。

 

输出格式:

 

输出文件foodshop.out仅包含一个实数,四舍五入保留恰好一位小数,表示最佳快餐店选址距离最远用户的距离。

注意:你的结果必须恰好有一位小数,小数位数不正确不得分。

 

输入输出样例

输入样例#1:
【样例输入1】
4 
1 2 1 
1 4 2 
1 3 2 
2 4 1
【样例输入2】
5
1 5 100
2 1 77
3 2 80
4 1 64
5 3 41
输出样例#1:
【样例输出1】
2.0 
【样例输出2】
109.0

说明

样例1

技术分享

样例2

技术分享

数据范围

对于 10%的数据,N<=80,Li=1;

对于 30%的数据,N<=600,Li<=100;

对于 60% 的数据,N<=2000,Li<=10^9;

对于 100% 的数据,N<=10^5,Li<=10^9

显然这是一棵基环树.
那么先考虑树上的做法,答案就是直径/2.
现在有一个环了,那么最长链就有可能经过环上的点.
把环上的每条边去掉之后跑直径,然后取一个最小值就是答案了.
这样的复杂度是n^2,但只TLE4个点?但还有WA,不知道是写错了还是什么原因.
最长链要么在某一棵子树里,要么由某两颗子树的最长链和环上的一段组成.
那么就先预处理出每棵子树中的最长链,记为dis.
然后把环上的点记一个起点,记一个前缀和.
那么就设pre[i]i之前的点组成的最长链的长度,suf类似.
最后枚举每一条边,分三种情况取最大值就是断这一条边的答案.
复杂度O(n).


 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<string>
 6 #include<algorithm>
 7 #include<map>
 8 #include<complex>
 9 #include<queue>
10 #include<stack>
11 #include<cmath>
12 #include<set>
13 #include<vector>
14 #define maxn 100010
15 #define mk make_pair
16 #define LL long long
17 #define inf 1e17
18 using namespace std;
19 struct data{
20   int nex,to,w;
21 }e[maxn*2];
22 int head[maxn],edge=-1,dad[maxn],n;
23 LL dis[maxn],pre[maxn],suf[maxn],p1[2][maxn],p2[2][maxn],sum[2][maxn],ans=0;
24 bool flag=0,bj[maxn],huan[maxn];
25 vector<int>clc,eg;
26 map<pair<int,int>,int>mp;
27 queue<int>q;
28 inline void add(int from,int to,int w){
29   e[++edge].nex=head[from];
30   e[edge].to=to;
31   e[edge].w=w;
32   head[from]=edge;
33 }
34 inline void out(int x){
35   if(flag) return;
36   int xx=x;x=dad[x];
37   while(x!=xx) clc.push_back(x),x=dad[x];
38   clc.push_back(xx);
39 }
40 void dfs(int x,int fa){
41   if(flag) return;
42   for(int i=head[x];i!=-1;i=e[i].nex){
43     int v=e[i].to;
44     if(v==fa) continue;
45     if(dad[v]) {dad[v]=x;out(v);flag=1;return;}
46     dad[v]=x;dfs(v,x);
47   }
48 }
49 void dp(int x,int fa){
50   for(int i=head[x];i;i=e[i].nex){
51     int v=e[i].to;
52     if(v==fa || huan[v]) continue;
53     dp(v,x);
54     ans=max(ans,dis[x]+dis[v]+e[i].w);
55     dis[x]=max(dis[v]+e[i].w,dis[x]);
56   }
57 }
58 int main(){
59   memset(head,-1,sizeof(head));
60   int x,y,z;
61   scanf("%d",&n);
62   for(int i=1;i<=n;i++)
63     scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z),mp[mk(x,y)]=edge,mp[mk(y,x)]=edge;
64   dad[1]=1,dfs(1,0);
65   for(int i=0;i<clc.size();i++) huan[clc[i]]=1;
66   for(int i=0;i<clc.size();i++) dp(clc[i],0);
67   int len=clc.size();
68   p1[0][0]=p2[0][0]=dis[clc[0]];pre[0]=-inf;
69   for(int i=1;i<len;i++){
70     int u=clc[i-1],v=clc[i];
71     sum[0][i]=sum[0][i-1]+e[mp[mk(u,v)]].w;
72     p1[0][i]=max(p1[0][i-1],dis[v]+sum[0][i]);
73     p2[0][i]=max(p2[0][i-1],dis[v]-sum[0][i]);
74     pre[i]=max(pre[i-1],dis[v]+sum[0][i]+p2[0][i-1]);
75   }
76   clc.push_back(clc[0]);
77   p1[1][len]=p2[1][len]=dis[clc[len]];suf[len]=-inf;
78   for(int i=len-1;i>0;i--){
79     int u=clc[i+1],v=clc[i];
80     sum[1][i]=sum[1][i+1]+e[mp[mk(u,v)]].w;
81     p1[1][i]=max(p1[1][i+1],dis[v]+sum[1][i]);
82     p2[1][i]=max(p2[1][i+1],dis[v]-sum[1][i]);
83     suf[i]=max(suf[i+1],dis[v]+sum[1][i]+p2[1][i+1]);
84   }
85   LL g=inf;
86   for(int i=1;i<len;i++){
87     LL now=p1[0][i-1]+p1[1][i];
88     now=max(now,max(pre[i-1],suf[i]));
89     g=min(g,now);
90   }
91   printf("%.1lf",(double)max(g,ans)/2);
92   return 0;
93 }

 






以上是关于[NOI2013]快餐店的主要内容,如果未能解决你的问题,请参考以下文章

[NOI2013]快餐店

BZOJ3242UOJ#126NOI2013快餐店

bzoj3242 [Noi2013]快餐店

bzoj 3242: [Noi2013]快餐店

BZOJ3242 [Noi2013]快餐店/UOJ126

Android - 如何显示包含从片段中获取的字符串的快餐栏