[Sdoi2013]直径

<body> <center><h1>3124: [Sdoi2013]直径</h1><span class="green">Time Limit: </span>10 Sec&nbsp;&nbsp;<span class="green">Memory Limit: </span>256 MB<br><span class="green">Submit: </span>1830&nbsp;&nbsp;<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&nbsp;条边。 路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用&nbsp;dis(a,b)<br> 表示点a和点b的路径上各边长度之和。称dis(a,b)为a、b两个节点间的距离。&nbsp; <br> &nbsp;直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。 <br> 现在小Q想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。 <br> </span></p></div><h2>Input</h2><div class="content"><p><font size="4">第一行包含一个整数N,表示节点数。 <br> 接下来N-1行,每行三个整数a, b, c&nbsp;,表示点&nbsp;a和点b之间有一条长度为c<br> 的无向边。&nbsp;</font></p></div><h2>Output</h2><div class="content"><p><font size="4">&nbsp; <br> 共两行。第一行一个整数,表示直径的长度。第二行一个整数,表示被所有<br> 直径经过的边的数量。&nbsp;<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> &nbsp;<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;
}

posted on 2019-06-12 17:02  autoint  阅读(102)  评论(0编辑  收藏  举报

导航