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
分析:首先,答案一定是环上去掉一条边后剩下树的“直径”的一半,于是我们枚举删边,然后用维护线段树来求过环上边的最长路径,代码写的巨丑。
#include<iostream>
#include<string>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<set>
#include<map>
#include<vector>
#include<cstring>
#include<stack>
#include<queue>
#define INF 0x3f3f3f3f
#define eps 1e-9
#define MOD 1000000007
#define MAX 100000047483647ll
#define N 100005
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
ll ans,Cir_len,MAXVAL,pre,Mans[N][2];
int n,u,v,val,jud[N],vis[N];
map <pii,ll> f;
vector <pii> G[N];
stack <int> S;
vector<int> a;
struct Tree
{
ll val[2],Down;
int cho[2];
}tree[2][4*N];
bool Circle(int u,int fa)
{
vis[u] = true;
S.push(u);
for(int i = 0;i < G[u].size();i++)
{
int v = G[u][i].first;
if(v != fa)
if(vis[v])
{
while(S.top() != v)
{
a.push_back(S.top());
S.pop();
}
a.push_back(v);
S.pop();
return true;
}
else
if(Circle(v,u)) return true;
}
S.pop();
return false;
}
void up_date(int u,pii Edge)
{
int v = Edge.first,val = Edge.second;
ll &a = Mans[u][0],&b = Mans[u][1];
a = max(a,Mans[v][1] + val);
if(a > b) swap(a,b);
}
void dfs(int u,int fa)
{
for(int i = 0;i < G[u].size();i++)
{
int v = G[u][i].first;
if(v != fa && !jud[v])
{
dfs(v,u);
up_date(u,G[u][i]);
}
}
MAXVAL = max(MAXVAL,Mans[u][0] + Mans[u][1]);
}
void Down(int op,int i)
{
if(tree[op][i].Down)
{
ll Down = tree[op][i].Down;
tree[op][i].Down = 0;
tree[op][2*i].Down += Down,tree[op][2*i+1].Down = Down;
tree[op][2*i].val[0] += Down,tree[op][2*i].val[1] += Down;
tree[op][2*i+1].val[0] += Down,tree[op][2*i+1].val[1] += Down;
}
}
void up(int op,int i)
{
tree[op][i].val[0] = tree[op][2*i].val[1];
tree[op][i].val[1] = tree[op][2*i+1].val[1];
tree[op][i].cho[0] = tree[op][2*i].cho[1];
tree[op][i].cho[1] = tree[op][2*i+1].cho[1];
if(tree[op][i].val[0] > tree[op][i].val[1])
{
swap(tree[op][i].val[0],tree[op][i].val[1]);
swap(tree[op][i].cho[0],tree[op][i].cho[1]);
}
}
void deal(int op,int i,int l,int r,int x,int y,ll val)
{
if(x > y) return;
if(l == x && r == y)
{
tree[op][i].Down += val;
tree[op][i].val[0] += val;
tree[op][i].val[1] += val;
if(x == y) tree[op][i].cho[0] = tree[op][i].cho[1] = x;
return;
}
Down(op,i);
int mid = (l + r) >> 1;
if(y <= mid) deal(op,2*i,l,mid,x,y,val);
else
if(x <= mid)
{
deal(op,2*i,l,mid,x,mid,val);
deal(op,2*i+1,mid+1,r,mid+1,y,val);
}
else deal(op,2*i+1,mid+1,r,x,y,val);
up(op,i);
}
void Up_date(ll &ans)
{
if(!tree[0][1].cho[1] || tree[0][1].cho[1] != tree[1][1].cho[1]) ans = min(ans,max(MAXVAL,tree[0][1].val[1] + tree[1][1].val[1]));
else
{
ll temp = max(tree[0][1].val[1] + tree[1][1].val[0],tree[0][1].val[0] + tree[1][1].val[1]);
ans = min(ans,max(MAXVAL,temp));
}
}
int main()
{
scanf("%d",&n);
for(int i = 1;i <= n;i++)
{
scanf("%d%d%d",&u,&v,&val);
G[u].push_back(make_pair(v,val));
G[v].push_back(make_pair(u,val));
pii temp1 = make_pair(u,v),temp2 = make_pair(v,u);
f[temp1] = f[temp2] = val;
}
Circle(1,-1);
for(int i = 0;i < a.size();i++)
{
int u = a[i];
jud[u] = true;
if(i) Cir_len += f[make_pair(u,a[i-1])];
else Cir_len += f[make_pair(u,a[a.size()-1])];
}
for(int i = 0;i < a.size();i++)
{
int u = a[i];
dfs(u,-1);
}
for(int i = 0;i < a.size();i++)
{
int u = a[i];
if(i) pre += f[make_pair(u,a[i-1])];
deal(0,1,1,a.size(),i+1,i+1,Mans[u][1] + pre);
deal(1,1,1,a.size(),i+1,i+1,Mans[u][1] - pre);
}
ans = MAX;
Up_date(ans);
for(int i = 0;i < a.size()-1;i++)
{
int u = a[i];
ll val = f[make_pair(u,a[i+1])];
deal(0,1,1,a.size(),i+2,a.size(),-1*val);
deal(0,1,1,a.size(),1,i,-1*val);
deal(0,1,1,a.size(),i+1,i+1,Cir_len - val);
deal(1,1,1,a.size(),i+2,a.size(),val);
deal(1,1,1,a.size(),1,i,val);
deal(1,1,1,a.size(),i+1,i+1,val - Cir_len);
Up_date(ans);
}
printf("%.1lf\n",ans*0.5);
}