[NOI2003]逃学的小孩
<body>
<center><h1>1509: [NOI2003]逃学的小孩</h1><span class="green">Time Limit: </span>5 Sec <span class="green">Memory Limit: </span>64 MB<br><span class="green">Submit: </span>1333 <span class="green">Solved: </span>693<br>[<a href="submitpage.php?id=1509">Submit</a>][<a href="problemstatus.php?id=1509">Status</a>][<a href="bbs.php?id=1509">Discuss</a>]</center><h2>Description</h2><div class="content">
<img border="0" src="https://www.lydsy.com/JudgeOnline/images/1509.jpg"></div><h2>Input</h2><div class="content">第一行是两个整数N(3 ≤ N ≤ 200000)和M,分别表示居住点总数和街道总数。以下M行,每行给出一条街道的信息。第i+1行包含整数Ui、Vi、Ti(1≤Ui, Vi ≤ N,1 ≤ Ti ≤ 1000000000),表示街道i连接居住点Ui和Vi,并且经过街道i需花费Ti分钟。街道信息不会重复给出。
</div><h2>Output</h2><div class="content">仅包含整数T,即最坏情况下Chris的父母需要花费T分钟才能找到Chris。
</div><h2>Sample Input</h2>
<div class="content"><span class="sampledata">4 3<br>
1 2 1<br>
2 3 1<br>
3 4 1<br>
</span></div><h2>Sample Output</h2>
<div class="content"><span class="sampledata">4<br>
</span></div><h2>HINT</h2>
<div class="content"><p></p></div><h2>Source</h2>
<div class="content"><p><a href="problemset.php?search="></a></p></div><center>[<a href="submitpage.php?id=1509">Submit</a>][<a href="problemstatus.php?id=1509">Status</a>][<a href="bbs.php?id=1509">Discuss</a>]</center><br>
<a href="./"><span class="red">HOME</span></a>
<a href="javascript:history.go(-1)"><span class="red">Back</span></a>
<hr>
</body>
题解
根据调整法可知,最优解一定经过直径。所以以直径的两个端点为根找出距离其他节点到两个根距离最小值的最大值,加上直径的长度就是答案了。
时间复杂度\(O(n)\)
#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;rg char ch=getchar();
for(;!isdigit(ch);ch=getchar())if(ch=='-') w=-w;
for(;isdigit(ch);ch=getchar()) data=data*10+ch-'0';
return data*w;
}
template<class T>il T read(rg T&x) {return x=read<T>();}
typedef long long ll;
using namespace std;
co int N=2e5+1;
int n,m;
ll d[N],f[N];
bool v[N];
vector<pair<int,int> > e[N];
void dfs(int x,int&o){
v[x]=1;
for(unsigned i=0;i<e[x].size();++i){
int y=e[x][i].first,z=e[x][i].second;
if(v[y]) continue;
d[y]=d[x]+z;
dfs(y,o);
}
v[x]=0;
if(d[x]>d[o]) o=x;
}
int main(){
read(n),read(m);
for(int i=1,x,y,z;i<n;++i){
read(x),read(y),read(z);
e[x].push_back(make_pair(y,z)),e[y].push_back(make_pair(x,z));
}
int s=1;
dfs(1,s);
int t=s;
d[s]=0;
dfs(s,t);
memcpy(f,d,sizeof f);
d[t]=0;
dfs(t,s);
ll ans=0;
for(int i=1;i<=n;++i)
ans=max(ans,min(d[i],f[i]));
printf("%lld\n",ans+f[t]);
return 0;
}
另外也可以枚举转折点找出前三长的边来求解。
静渊以有谋,疏通而知事。