您的位置:首页 > 其它

bzoj千题计划134:bzoj3124: [Sdoi2013]直径

2017-12-14 16:31 447 查看
http://www.lydsy.com/JudgeOnline/problem.php?id=3124

第一问:

dfs1、dfs2

dfs2中记录dis[i]表示点i距离最长链左端点的距离

第二问:

所有直径的交集一定是最长链上连续的一段

dfs3记录最长链,

从最长链上每个点i开始dfs4,记录能到达的非最长链点的最远距离mx

如果mx==最长链-dis[i],更新交集的左端点

如果mx==dis[i],找到交集的右端点,退出

#include<cstdio>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;
#define N 200001

int tot;
int front
,nxt[N<<1],to[N<<1],val[N<<1];

LL mx,max_len;
int wh;

LL dis
;

int path
,num;

bool use
;

int cf
;

void read(int &x)
{
x=0; char c=getchar();
while(!isdigit(c))  c=getchar();
while(isdigit(c)) { x=x*10+c-'0'; c=getchar();  }
}

void add(int u,int v,int w)
{
to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=w;
}

void dfs1(int x,int y,LL d)
{
if(d>mx) mx=d,wh=x;
for(int i=front[x];i;i=nxt[i])
{
if(to[i]==y) continue;
dfs1(to[i],x,d+val[i]);
}
}

void dfs2(int x,int y,LL d)
{
dis[x]=d;
if(d>max_len) max_len=d,wh=x;
for(int i=front[x];i;i=nxt[i])
{
if(to[i]==y) continue;
dfs2(to[i],x,d+val[i]);
}
}

void dfs3(int x,LL d)
{
path[++num]=x;
use[x]=true;
for(int i=front[x];i;i=nxt[i])
{
if(dis[to[i]]==d-val[i]) dfs3(to[i],d-val[i]);
}
}

void dfs4(int x,int y,LL d)
{
mx=max(mx,d);
for(int i=front[x];i;i=nxt[i])
{
if(to[i]==y || use[to[i]]) continue;
dfs4(to[i],x,d+val[i]);
}
}

int main()
{
int n;
read(n);
int u,v,w;
for(int i=1;i<n;++i)
{
read(u); read(v); read(w);
add(u,v,w);
}
dfs1(1,0,0);
dfs2(wh,0,0);
cout<<max_len<<'\n';
dfs3(wh,max_len);
int L=1,R=num;
for(int i=2;i<num;++i)
{
mx=0;
dfs4(path[i],0,0);
if(mx==max_len-dis[path[i]]) L=i;
if(mx==dis[path[i]]) { R=i; break; }
}
cout<<R-L;
}


3124: [Sdoi2013]直径

Time Limit: 10 Sec Memory Limit: 256 MB
Submit: 1261 Solved: 603
[Submit][Status][Discuss]

Description

小Q最近学习了一些图论知识。根据课本,有如下定义。树:无回路且连通的无向图,每条边都有正整数的权值来表示其长度。如果一棵树有N个节点,可以证明其有且仅有N-1 条边。 路径:一棵树上,任意两个节点之间最多有一条简单路径。我们用 dis(a,b)
表示点a和点b的路径上各边长度之和。称dis(a,b)为a、b两个节点间的距离。
直径:一棵树上,最长的路径为树的直径。树的直径可能不是唯一的。
现在小Q想知道,对于给定的一棵树,其直径的长度是多少,以及有多少条边满足所有的直径都经过该边。

Input

第一行包含一个整数N,表示节点数。
接下来N-1行,每行三个整数a, b, c ,表示点 a和点b之间有一条长度为c
的无向边。

Output

共两行。第一行一个整数,表示直径的长度。第二行一个整数,表示被所有
直径经过的边的数量。

Sample Input

6

3 1 1000

1 4 10

4 2 100

4 5 50

4 6 100

Sample Output

1110

2

【样例说明】

直径共有两条,3 到2的路径和3到6的路径。这两条直径都经过边(3, 1)和边(1, 4)。

HINT

对于100%的测试数据:2≤N≤200000,所有点的编号都在1..N的范围内,

边的权值≤10^9。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: