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

浙公网安备 33010602011771号