bzoj 3242: [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 2 1

1 4 2

1 3 2

2 4 1

Sample Output

2.0

HINT

数据范围

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

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

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

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

Source

我们发现对于最优点,必然存在两个点,和最优点距离相等而且是最远点,

那么答案就是这两个最远点的距离/2,(其余点的与最优点的距离不会超过该答案,不然最远点就会变,跟着最优点的位置也会变);

然后我们要求这个答案尽量小,这也说明了直接求图的直径/2是错误的;

我们考虑最优点与两个最远点的路径,一种就是在一棵树中,那么答案为直径/2;

第二种就是从一棵树走到根,通过环,走到另一棵树中,即x的子树->x->y->y的子树

我们发现这样的话,我们断掉环上的一条边,是不会影响答案的;

那么我们将问题转化为,断掉环上的一条边,求直径;

我们现在只考虑要经过环的路径(不在环上的把每棵树的直径去Max即可);

我们对于环上的每个点往下求出在其子树内最多能走多远,记为d[i];

然后我们现在断了一条环上的边,最优答案有两种:

1.x,y在断开的边的两侧,那么我们把顺时针的距离记为sum1,逆时针的距离记为sum2;

那么最优答案就是一侧的 Max{sum1i+d[i]}+另一侧的Max{sum2i+d[i]};

这就类似于前缀最大值和后缀最大值相加,前缀最大值和后缀最大值显然是可以通过数组递推实现的;

2.x,y在断开的边的同侧:

我们只考虑走顺时针方向的一侧;

那么答案就是Max{d[x]+d[y]+sum1[y]-sum1[x]}{sum1[y]>sum1[x]);

我们发现合并下标相同的变为: sum1[y]+d[y]-sum1[x]+d[x];

对于每一个y,需要的就是Max{-sum1[x]+d[x]}{sum1[x]<sum1[y])

这显然也可以在递推的时候用一个前缀最大值来实现;

在逆时针一侧的同理,记后缀最大值即可;

没开long long 怀疑人生;

//MADE BY QT666
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define int long long
#define lson x<<1
#define rson x<<1|1
using namespace std;
typedef long long ll;
const int N=300050;
int fa[N],dfn[N],tt,head[N],to[N],nxt[N],w[N],cnt;
int len,cir[N],v[N],dis[N],bj[N],n,d[N],p[N],f[N],ans;
int pre[N],suf[N],tc1[N],tc2[N];
void lnk(int x,int y,int z){
    to[++cnt]=y,nxt[cnt]=head[x],w[cnt]=z,head[x]=cnt;
    to[++cnt]=x,nxt[cnt]=head[y],w[cnt]=z,head[y]=cnt;
}
void getrt(int rt,int x){
  for(int u=x;u!=fa[rt];u=fa[u])
      cir[++len]=u,v[len+1]=dis[u],bj[u]=1;
}
void Tarjan(int x,int ff){
  dfn[x]=++tt;fa[x]=ff;
  for(int i=head[x];i;i=nxt[i]){
    int y=to[i];
    if(!dfn[y]) dis[y]=w[i],Tarjan(y,x);
    else if(dfn[y]>dfn[x]) v[1]=w[i],getrt(x,y);
  }
}
void dfs(int x,int ff,int top){
    for(int i=head[x];i;i=nxt[i]){
	int y=to[i];if(y==ff||bj[y]) continue;
	dfs(y,x,top);
	p[top]=max(p[top],f[x]+f[y]+w[i]);f[x]=max(f[x],f[y]+w[i]);
    }
}
main(){
    freopen("foodshop.in","r",stdin);
    freopen("foodshop.out","w",stdout);
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){int x,y,z;scanf("%lld%lld%lld",&x,&y,&z);lnk(x,y,z);}
    Tarjan(1,0);
    for(int i=1;i<=len;i++) dfs(cir[i],cir[i],cir[i]),d[cir[i]]=f[cir[i]];
    int ans=1ll<<60,sum,pr;sum=0,pr=0;
    for(int i=2;i<=len;i++){
	pre[i]=max(pre[i-1],sum+d[cir[i-1]]);
	tc1[i]=max(tc1[i-1],sum+d[cir[i-1]]+pr);
	pr=max(pr,d[cir[i-1]]-sum);
	sum+=v[i];
    }
    pre[1]=max(pre[len],sum+d[cir[len]]);
    tc1[1]=max(tc1[len],sum+d[cir[len]]+pr);
    sum=0;sum+=v[1];suf[len]=sum+d[cir[len]];
    pr=d[cir[len]]-sum;
    for(int i=len-1;i>=2;i--){
	suf[i]=max(suf[i+1],sum+d[cir[i]]+v[i+1]);
	tc2[i]=max(tc2[i+1],sum+d[cir[i]]+v[i+1]+pr);
	pr=max(pr,d[cir[i]]-(sum+v[i+1]));
	sum+=v[i+1];
    }
    for(int i=1;i<=len;i++){
	ans=min(ans,max(pre[i]+suf[i],max(tc1[i],tc2[i])));
    }
    int tmp=0;
    for(int i=1;i<=len;i++){
	tmp=max(tmp,p[cir[i]]);
	ans=max(ans,p[cir[i]]);
    }
    printf("%.1f\n",1.0*ans/2);
    return 0;
}
时间: 2024-09-30 11:16:46

bzoj 3242: [Noi2013]快餐店的相关文章

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

3242: [Noi2013]快餐店 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 266  Solved: 140[Submit][Status] Description 小 T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近 的地方. 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两

3242: [Noi2013]快餐店 - BZOJ

Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两个建筑.任意两个建筑之间至少存在一条由双向道路连接而成的路径.小T的快餐店可以开设在任一建筑中,也可以开设在任意一条道路的某个位置上(该位置与道路两端的建筑的距离不一定是整数). 现给定城市C的地图(道路

[noi2013]快餐店 基环树dp,单调队列维护最大值和次大值

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 220000 #define inf 0x3ffffffffffffffLL typedef long long ll; int v[N],e[N],ne[N],nn,w[N]; void add(int x,int y,int z){ ne[++nn

【BZOJ 3242】【UOJ #126】【CodeVS 3047】【NOI 2013】快餐店

http://www.lydsy.com/JudgeOnline/problem.php?id=3242 http://uoj.ac/problem/126 http://codevs.cn/problem/3047/ 因为存在一条边,答案所在的点走向左右的城的最短路都不会经过这条边. 所以枚举这条边,剩下的用线段树维护. 线段树初始化搞了好久,忘了在外向树上做dp,树形dp时记录也错了,总之调了一天,吃枣药丸啊QwQ 时间复杂度$O(nlogn)$,听说有$O(n)$的单调队列做法,留一个坑以

bzoj3242 [Noi2013]快餐店

Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两个建筑.任意两个建筑之间至少存在一条由双向道路连接而成的路径.小T的快餐店可以开设在任一建筑中,也可以开设在任意一条道路的某个位置上(该位置与道路两端的建筑的距离不一定是整数). 现给定城市C的地图(道路

[NOI2013]快餐店

题目描述 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两个建筑.任意两个建筑之间至少存在一条由双向道路连接而成的路径.小T的快餐店可以开设在任一建筑中,也可以开设在任意一条道路的某个位置上(该位置与道路两端的建筑的距离不一定是整数). 现给定城市C的地图(道路分布及其长度)

BZOJ3242 [Noi2013]快餐店/UOJ126

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/转载请注明出处,侵权必究,保留最终解释权! Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连

动态规划:NOI2013 快餐店

Description 小 T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近 的地方. 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两个建筑.任意两个建筑之间至少存在一条由双向道路连接而成的路径.小T的快餐店可以开设在任一建筑 中,也可以开设在任意一条道路的某个位置上(该位置与道路两端的建筑的距离不一定是整数). 现给定城市C的地图

bzoj 3240: [Noi2013]矩阵游戏 矩阵乘法+十进制快速幂+常数优化

3240: [Noi2013]矩阵游戏 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 613  Solved: 256[Submit][Status] Description 婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的n行m列的矩阵(你不用担心她如何存储).她生成的这个矩阵满足一个神奇的性质:若用F[i][j]来表示矩阵中第i行第j列的元素,则F[i][j]满足下面的递推式: F[1][1]=1F[i,j]=a*F[i][j-1]+