P1399 [NOI2013] 快餐店 题解

题目链接

完成学习后,感觉也没有那么难?

思路

这道题,本质上就是在求基环树的直径,/2 就好了。于是问题变成高效求基环树的直径。

什么是基环树的直径

就是断环上的任意一条边形成的树的直径的最小值。

但是根据定义求,肯定会TLE,考虑优化。

看到环,拆环成链,那么显然一段长度为 \(len\) 的环就变成了 \(len\) 个区间。

那么对于一段区间,显然其直径就是 \(max(dep_u+dep_v+dis_{x,y})\),然后 \(dis_{x,y}\) 又能够用前缀和计算,因此再拆下贡献,就是 \(dep_u+sum_u\)\(dep_v-sum_v\) 的最大值,开堆维护一下就好了。

时间复杂度 $O(n \log n) $。

Code

#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define File(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout)
#define LL long long
#define fi first
#define se second
const int N = 1e5 + 10;
const LL inf = (1ll << 60);
int n;
vector< pair<int,int> > G[N];
int dfn[N];
pair<int,int> cir[N << 1],pre[N];
int tot = 0;
int len = 0;
LL dep[N];
bool vis[N];
LL ans = 0;
void tarjan(int u){
	dfn[u] = ++tot;
	for(pair<int,int>x : G[u]){
		int v = x.fi,w = x.se;
		if(v == pre[u].fi) continue;
		if(dfn[v] == 0){
			pre[v] = {u,w};
			tarjan(v);
		}
		else if(dfn[v] > dfn[u]){
			cir[++len] = {v,w};
			for(int nw=v;;nw=pre[nw].fi){
				cir[++len] = pre[nw];
				if(pre[nw].fi == u) break;
			}
		}
	}
	return ;
}
void calc(int u){
	vis[u] = 1; 
	for(pair<int,int> x : G[u]){
		int v = x.fi,w = x.se;
		if(vis[v]) continue;
		calc(v);
		ans = max(ans,dep[u] + dep[v] + 1ll * w);
		dep[u] = max(dep[u],dep[v] + 1ll * w);
	}
	return ;
}
LL sum[N << 1],g[N << 1];
struct cmp1{
	bool operator()(int x,int y){
		return sum[x] + g[x] < sum[y] + g[y];
	}
};
struct cmp2{
	bool operator()(int x,int y){
		return g[x] - sum[x] < g[y] - sum[y];
	}
};
priority_queue< int,vector<int>,cmp1> q1;
priority_queue< int,vector<int>,cmp2> q2;
int main()
{
	IOS;
	cin >> n;
	for(int i=1;i<=n;i++){
		int u,v,w;
		cin >> u >> v >> w;
		G[u].push_back({v,w});
		G[v].push_back({u,w});
	}
	tarjan(1);
	for(int i=1;i<=len;i++) vis[cir[i].fi] = 1;
	for(int i=1;i<=len;i++) calc(cir[i].fi);
	for(int i=1;i<=len;i++){
		sum[i] = sum[i-1] + 1ll * cir[i].se;
		g[i] = dep[cir[i].fi];
		q1.push(i);
		q2.push(i);
	}
	for(int i=len+1;i<=len*2;i++){
		sum[i] = sum[i-1] + 1ll * cir[i-len].se;
		g[i] = dep[cir[i-len].fi];
	}
	LL D = inf;
	for(int i=1;i<=len;i++){
		while(!q1.empty() && q1.top() < i) q1.pop();
		while(!q2.empty() && q2.top() < i) q2.pop();
		int x = q1.top(),y = q2.top();
		if(x == y){
			q1.pop();q2.pop();
			while(!q1.empty() && q1.top() < i) q1.pop();
			while(!q2.empty() && q2.top() < i) q2.pop();
			if(!q1.empty()){
				int gx=q1.top(),gy=q2.top();
				D = min(D,max(sum[x] + g[x] - sum[gy] + g[gy],sum[gx] + g[gx] - sum[x] + g[x]));
			}
			q1.push(x);
			q2.push(x);
		}
		else{
			D = min(D,sum[x] + g[x] - sum[y] + g[y]);
		}
		q1.push(i+len);
		q2.push(i+len);
	}
	ans = max(ans,D);
	cout << ans / 2ll <<'.'<< (((ans & 1ll) == 1) ? 5 : 0);
	return 0;
}
posted @ 2026-01-12 20:57  WinterXorSnow  阅读(3)  评论(0)    收藏  举报