Bzoj-3242 快餐店(环套树)

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);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值