zoukankan      html  css  js  c++  java
  • bzoj 3124 [Sdoi2013]直径(dfs)

    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。

    【思路】

           dfs

           第一问两遍dfs可以求出。

           对于第二问,首先被所有直径经过的边一定可以在一条直径上找到,其次他们在直径上是连续的否则就不是一棵树

           然后依次枚举一条直径上的结点,对当前结点dfs得到不经过直径上的点的最长边,如果与目前点到枚举起点的距离相同则说明直径发生了分叉,L挪到当前点;如果与当前点到枚举终点的距离相同则说明直径发生了“反向”分叉,停止枚举此时区间确定为当前指针R和L。

           至于时间因为我们是从直径出发dfs而且不经过直径,所以每个点至多被访问一次,时间为O(n)

    【代码】

     1 #include<cmath>
     2 #include<queue>
     3 #include<vector>
     4 #include<cstdio>
     5 #include<cstring>
     6 #include<iostream>
     7 #include<algorithm>
     8 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
     9 using namespace std;
    10 
    11 typedef long long LL;
    12 const int N = 2*1e5+10;
    13 struct Edge { int u,v,w;
    14 };
    15 vector<Edge> es;
    16 vector<int> g[N];
    17 
    18 int n,vis[N];
    19 
    20 void read(int& x) {
    21     char c=getchar(); int f=1; x=0;
    22     while(!isdigit(c)) {if(c=='-')f=-1; c=getchar();}
    23     while(isdigit(c)) x=x*10+c-'0',c=getchar();
    24     x*=f;
    25 }
    26 void adde(int u,int v,int w) {
    27     es.push_back((Edge){u,v,w});
    28     g[u].push_back((int)es.size()-1);
    29 }
    30 
    31 LL maxdis; int maxu,pa[N];
    32 void dfs(int u,int fa,LL d) {
    33     if(d>maxdis) maxdis=d,maxu=u;
    34     for(int i=0;i<g[u].size();i++) {
    35         Edge& e=es[g[u][i]];
    36         int v=e.v;
    37         if(v!=fa) {
    38             pa[v]=g[u][i];
    39             dfs(v,u,e.w+d);
    40         }
    41     }
    42 }
    43 void dfs2(int u,int fa,LL d) {
    44     if(d>maxdis) maxdis=d;
    45     for(int i=0;i<g[u].size();i++) {
    46         Edge& e=es[g[u][i]];
    47         int v=e.v;
    48         if(v!=fa && !vis[v]) dfs2(v,u,d+e.w); 
    49     }
    50 }
    51 
    52 int main() {
    53     read(n);
    54     int u,v,w;
    55     FOR(i,1,n-1) {
    56         read(u),read(v),read(w);
    57         adde(u,v,w),adde(v,u,w);
    58     }
    59     maxdis=0; dfs(1,-1,0); 
    60     int x=maxu;
    61     maxdis=0; dfs(x,-1,0); 
    62     LL ans=maxdis; int y=maxu;
    63     
    64     printf("%lld
    ",ans);
    65     for(int i=y;i!=x;i=es[pa[i]].u) vis[i]=1;
    66     vis[x]=1;
    67     int l=0,r=0; LL nowdis=0;
    68     for(int i=y;i;i=es[pa[i]].u) {
    69         Edge& e=es[pa[i]];
    70         r++;
    71         maxdis=0; dfs2(i,-1,0);
    72         if(maxdis==nowdis) l=r;
    73         if(maxdis==ans-nowdis) break;
    74         nowdis+=e.w;
    75     }
    76     printf("%d",r-l);
    77     return 0;
    78 }
  • 相关阅读:
    WIA Property Constant Definitions
    未能导入activex控件,请确保它正确注册"的完美解决方案
    ILSpy反编译工具的使用
    WIA
    在C#中使用WIA获取扫描仪数据
    在C#中使用WIA获取扫描仪数据(利用Filter处理图片)
    VS2010中,无法嵌入互操作类型“……”,请改用适用的接口的解决方法
    怎么添加项目到SVN上面
    数学家帮你找出最佳求职者 你只要先淘汰前37%的人
    程序员7大软技能测验 你得几分?
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5232315.html
Copyright © 2011-2022 走看看