[Sdoi2013]直径
<body>
<center><h1>3124: [Sdoi2013]直径</h1><span class="green">Time Limit: </span>10 Sec <span class="green">Memory Limit: </span>256 MB<br><span class="green">Submit: </span>1830 <span class="green">Solved: </span>882<br>[<a href="submitpage.php?id=3124">Submit</a>][<a href="problemstatus.php?id=3124">Status</a>][<a href="bbs.php?id=3124">Discuss</a>]</center><h2>Description</h2><div class="content"><p><span style="font-size: medium">小Q最近学习了一些图论知识。根据课本,有如下定义。树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度。如果一棵树有N个节点,可以证明其有且仅有N-1 条边。 路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用 dis(a,b)<br>
表示点a和点b的路径上各边长度之和。称dis(a,b)为a、b两个节点间的距离。 <br>
直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。 <br>
现在小Q想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。 <br>
</span></p></div><h2>Input</h2><div class="content"><p><font size="4">第一行包含一个整数N,表示节点数。 <br>
接下来N-1行,每行三个整数a, b, c ,表示点 a和点b之间有一条长度为c<br>
的无向边。 </font></p></div><h2>Output</h2><div class="content"><p><font size="4"> <br>
共两行。第一行一个整数,表示直径的长度。第二行一个整数,表示被所有<br>
直径经过的边的数量。 <br>
</font></p></div><h2>Sample Input</h2>
<div class="content"><span class="sampledata"> <br>
6 <br>
3 1 1000<br>
1 4 10<br>
4 2 100<br>
4 5 50<br>
4 6 100<br>
</span></div><h2>Sample Output</h2>
<div class="content"><span class="sampledata">1110 <br>
2 <br>
<br>
<br>
【样例说明】 <br>
直径共有两条,3 到2的路径和3到6的路径。这两条直径都经过边(3, 1)和边(1, 4)。</span></div><h2>HINT</h2>
<div class="content"><p></p><p><span style="font-size: medium">对于100%的测试数据:2≤N≤200000,所有点的编号都在1..N的范围内,<br><br>
<br><br>
边的权值≤10^9。</span></p><p></p></div><h2>Source</h2>
<div class="content"><p><a href="problemset.php?search="></a></p></div><center>[<a href="submitpage.php?id=3124">Submit</a>][<a href="problemstatus.php?id=3124">Status</a>][<a href="bbs.php?id=3124">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>
题解
直径的必须边一定是连续的一段。证明:假如有分开的,那么中间就有环,与树不符。所以是连续的一段。
直径就两边dfs,找必须边就先尽量向下走,走到一端后尽量向上走。能走的条件:把直径当成根求深度,若分支深度等于直径剩余的长,则出现了直径分叉,不能继续走了。
时间复杂度\(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,p[N],q[N];
bool v[N];
ll d[N],f[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;
p[y]=x;
dfs(y,o);
}
v[x]=0;
if(d[x]>d[o]) o=x;
}
int main(){
read(n);
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]=p[s]=0;
dfs(s,t);
printf("%lld\n",d[t]);
for(int i=t;i;i=p[i]){
v[i]=1;
q[p[i]]=i;
}
for(int x=t;x;x=p[x]){
f[x]=0;
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]=z;
int w=y;
dfs(y,w);
f[x]=max(f[x],d[w]);
}
}
int i,ans=0;
for(i=s;i;i=q[i]) // down
if(d[t]-d[i]==f[i]) break;
for(;i;i=p[i]){ // up
if(d[i]==f[i]) break;
++ans;
}
printf("%d\n",ans);
return 0;
}
静渊以有谋,疏通而知事。