码迷,mamicode.com
首页 > 其他好文 > 详细

[Sdoi2013] 直径

时间:2017-11-04 00:27:14      阅读:312      评论:0      收藏:0      [点我收藏+]

标签:return   nbsp   ret   down   getchar   namespace   输入   根据   sample   

[Sdoi2013]直径

时间限制: 1 Sec  内存限制: 256 MB

题目描述

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

输入

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

输出

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

样例输入

 
6 
3  1 1000
1  4 10
4  2 100
4  5 50
4  6 100

样例输出

1110 
2 
 
【样例说明】 
直径共有两条,3 到2的路径和3到6的路径。这两条直径都经过边(3, 1)和边(1, 4)。

提示

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

Solution:
    自己瞎yy了一下,然后就过了,很懵逼。直径很好求,求完以后直接记录一下直径上的点然后检查一下是否还有等长的就好。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 using namespace std;
 6 #define int long long
 7 #define N 200005
 8 #define root 1
 9 int read() {
10     int s=0,f=1;
11     char ch=getchar();
12     for( ; ch<0||ch>9; f=(ch==-)?-1:f,ch=getchar()) ;
13     for( ; ch>=0&&ch<=9; s=s*10+(ch^48),ch=getchar()) ;
14     return s*f;
15 }
16 int n,tot,r[N],Fa[N],low,high,Dis,deep[N],dis[N],Ans2;
17 struct oo {int fr,to,next,vv;} c[N<<1|1];
18 bool vis[N],Up[N],Down[N];
19 void add(int x,int y,int z) {
20     c[++tot].fr=x;
21     c[tot].to=y;
22     c[tot].vv=z;
23     c[tot].next=r[x];
24     r[x]=tot;
25 }
26 void dfs1(int u,int f,int d) {
27     if(d>Dis) Dis=d,low=u;
28     for(int i=r[u]; ~i; i=c[i].next) if(c[i].to!=f) dfs1(c[i].to,u,d+c[i].vv);
29 }
30 void dfs2(int u,int f) {
31     if(deep[u]>Dis) Dis=deep[u],high=u;
32     for(int i=r[u]; ~i; i=c[i].next) {
33         if(c[i].to!=f) {
34             Fa[c[i].to]=u,dis[c[i].to]=dis[u]+1;
35             deep[c[i].to]=deep[u]+c[i].vv;
36             dfs2(c[i].to,u);
37         }
38     }
39 }
40 void dfs(int u,int f,int d,int &mx) {
41     mx=max(mx,d);
42     for(int i=r[u]; ~i; i=c[i].next) if(c[i].to!=f&&!vis[c[i].to]) dfs(c[i].to,u,d+c[i].vv,mx);
43 }
44 signed main() {
45     n=read();
46     memset(r,0xff,sizeof(r));
47     for(int x,y,z,i=1; i<n; ++i) {
48         x=read(),y=read(),z=read();
49         add(x,y,z),add(y,x,z);
50     } dfs1(root,root,0); Dis=0; dfs2(low,low);
51     for(int i=high; i!=low; i=Fa[i]) vis[i]=true;
52     vis[low]=true;
53     for(int i=high,mx=0; ; i=Fa[i],mx=0) {
54         dfs(i,i,0,mx);
55         if(mx==deep[i]) Up[i]=true;
56         if(mx==Dis-deep[i]) Down[i]=true;
57         if(i==low) break;
58     } int pos1=0,pos2=0;
59     for(int i=high; ; i=Fa[i]) {
60         if(Up[i]&&!pos1) pos1=i;
61         if(Down[i]) pos2=i;
62         if(i==low) break;
63     } Ans2=dis[pos2]-dis[pos1];
64     if(Ans2<0) Ans2=0;
65     printf("%lld\n%lld",Dis,Ans2);
66     return 0;
67 }

 

[Sdoi2013] 直径

标签:return   nbsp   ret   down   getchar   namespace   输入   根据   sample   

原文地址:http://www.cnblogs.com/forevergoodboy/p/7780532.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!