[SDOI2013]直径 题解

题面

这道题明显的一定要找到直径的具体路径,所以两遍dfs是比较好的选择;

第一问是一道弱智题吧?

主要难度全部分摊在了第二问;

其实不难,先找到任意一个直径;

对于任意一个在直径上的点:

设nxt[i]表示这个点的下一个位置,pre[i]表示这个点的上一个位置;

ls[i]表示这个点到直径的左端点的距离,rs[i]则表示这个点到直径的右端点的距离;

我们再dfs一遍,找到每个点在不经过直径上任意点的时候所能到达的最远处,这个值记为dismax[i];

那么我们从直径的左端点开始向右推进,直到找到一个点的rs[i]=dismax[i](这意味着存在一条直径使得下一条边不是必经边);

我们注意到,从右向左也需要这么做一次。毕竟我们无法保证从左端点开始就是必经边;

然后就可以A掉了;

 

#include <bits/stdc++.h>
#define int long long
#define inc(i,a,b) for(register int i=a;i<=b;i++)
using namespace std;
const int MXR=2e5+10;
int head[MXR],cnt;
class littlestar{
	public:
	int to,nxt,w;
	void add(int u,int v,int gg){
		to=v; nxt=head[u]; 
		w=gg;head[u]=cnt;
	}
}star[MXR<<1];
int n,m;
template<class nT>
void read(nT& x)
{
	char c;while(c=getchar(),!isdigit(c));
	x=c^48;while(c=getchar(),isdigit(c)) x=x*10+c-48;
}
int dis[MXR],root1,root2,f[MXR],g[MXR];
void dfs(int u,int fa)
{
	f[u]=fa;
	for(int i=head[u];i;i=star[i].nxt){
		int v=star[i].to;
		if(v==fa) continue;
		dis[v]=dis[u]+star[i].w;
		dfs(v,u);
		g[v]=star[i].w;
	}
}
int judge[MXR],ls[MXR],rs[MXR],nxt[MXR],pre[MXR];
int dismax[MXR];
void dfs2(int u,int fa)
{
	for(int i=head[u];i;i=star[i].nxt){
		int v=star[i].to;
		if(v==fa) continue;
		dfs2(v,u);
		if(judge[v]==0){
			dismax[u]=max(dismax[u],star[i].w+dismax[v]);
		}
	}
}
signed main()
{
	read(n);
	inc(i,1,n-1){
		int a,b,c;
		read(a);read(b);read(c);
		star[++cnt].add(a,b,c);
		star[++cnt].add(b,a,c);
	}
	root1=1;
	dfs(root1,0);
	int maxn=-INT_MAX;
	inc(i,1,n) if(dis[i]>maxn) maxn=dis[i],root2=i;
	memset(dis,0,sizeof(dis)); maxn=-INT_MAX; memset(f,0,sizeof(f));
	dfs(root2,0);
	inc(i,1,n) if(dis[i]>maxn) maxn=dis[i],root1=i;
	int tmpx=root1;
	while(tmpx!=root2){
		nxt[tmpx]=f[tmpx];
		pre[f[tmpx]]=tmpx;		
		ls[f[tmpx]]=ls[tmpx]+g[tmpx];
		rs[tmpx]=maxn-ls[tmpx];
		judge[tmpx]=1;
		tmpx=f[tmpx];
	}
	judge[root2]=1;
	dfs2(root2,0);
	int goal=0;
	tmpx=root1;
	while(tmpx!=0){
		if(rs[tmpx]==dismax[tmpx]){
			break;
		}
		tmpx=nxt[tmpx];
	}
	if(tmpx==0) tmpx=pre[tmpx];
	goal=tmpx;
	while(tmpx!=0){
		if(ls[tmpx]==dismax[tmpx]){
			break;
		}
		tmpx=pre[tmpx];
	}
	if(tmpx==0) tmpx=nxt[tmpx];
	int ans=0;
	while(tmpx!=goal){
		++ans;
		tmpx=nxt[tmpx];
	}
	cout<<maxn<<endl;
	cout<<ans;
	
}
/*
6
3  1 1000
1  4 10
4  2 100
4  5 50
4  6 100
*/

 

 

 

posted @ 2019-11-05 16:03  神之右大臣  阅读(176)  评论(0编辑  收藏  举报