zoukankan      html  css  js  c++  java
  • [SDOI2013]直径

    题目大意:
      给你一棵n个结点的带边权的树,求该树直径必经边的个数。

    思路:
      显然直径必经的所有边的肯定是一个直径上的连续一段。
      (若超过一段,则出现环,就不是树了)
      首先求出原树的任一直径。
      预处理出该直径上从结点i出发,不经过直径上其它结点的最长链长度far[i]。
      从直径的两端往里缩,如果当前缩到的点i的far[i]等于i到被缩的那一端的距离,就说明直径的这一段至少有两种不重合的情况,肯定不是必经部分。
      最后看一下中间没有被缩的部分经过了几个边。

     1 #include<cstdio>
     2 #include<cctype>
     3 #include<vector>
     4 typedef long long int64;
     5 inline int getint() {
     6     register char ch;
     7     while(!isdigit(ch=getchar()));
     8     register int x=ch^'0';
     9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    10     return x;
    11 }
    12 const int N=200001;
    13 struct Edge {
    14     int to,w;
    15 };
    16 std::vector<Edge> e[N];
    17 inline void add_edge(const int &u,const int &v,const int &w) {
    18     e[u].push_back((Edge){v,w});
    19     e[v].push_back((Edge){u,w});
    20 }
    21 bool mark[N];
    22 int from[N],to[N],u,v;
    23 int64 dis[N],far[N];
    24 void dfs(const int &x) {
    25     for(unsigned i=0;i<e[x].size();i++) {
    26         const int &y=e[x][i].to,&w=e[x][i].w;
    27         if(y==from[x]) continue;
    28         from[y]=x;
    29         dis[y]=dis[x]+w;
    30         dfs(y);
    31     }
    32 }
    33 void dp(const int &x,const int &par) {
    34     for(unsigned i=0;i<e[x].size();i++) {
    35         const int &y=e[x][i].to,&w=e[x][i].w;
    36         if(y==par||mark[y]) continue;
    37         dp(y,x);
    38         far[x]=std::max(far[x],far[y]+w);
    39     }
    40 }
    41 int main() {
    42     const int n=getint();
    43     for(register int i=1;i<n;i++) {
    44         const int u=getint(),v=getint(),w=getint();
    45         add_edge(u,v,w);
    46     }
    47     dfs(1);
    48     for(register int i=1;i<=n;i++) {
    49         if(dis[i]>dis[u]) u=i;
    50     }
    51     dis[u]=from[u]=0;
    52     dfs(u);
    53     for(register int i=1;i<=n;i++) {
    54         if(dis[i]>dis[v]) v=i;
    55     }
    56     for(register int x=v;x;x=from[x]) {
    57         mark[x]=true;
    58         to[from[x]]=x;
    59     }
    60     for(register int x=v;x;x=from[x]) {
    61         dp(x,0);
    62     }
    63     int l=u,r=v;
    64     for(register int x=v;x;x=from[x]) {
    65         if(far[x]==dis[v]-dis[x]) r=x;
    66     }
    67     for(register int x=u;x;x=to[x]) {
    68         if(far[x]==dis[x]) l=x;
    69     }
    70     int len=0;
    71     for(register int x=r,i=0;x;x=from[x],i++) {
    72         if(x==l) len=i;
    73     }
    74     printf("%lld
    %d
    ",dis[v],len);
    75     return 0;
    76 }
  • 相关阅读:
    Java-Android 之动画的实现
    Java-Android 之出滚动条和卷轴页面
    Java-Android 之页面的跳转和结构的搭建
    Java-Android 之Hello World
    Java-struts2 之值栈问题
    Java-Hirbernate中文乱码问题
    Java-struts2 之中文乱码问题
    SQL SERVER2005事务日志已满 解决方法
    解决:对 PInvoke 函数的调用导致堆栈不对称问题
    webclient下载文件 带进度条
  • 原文地址:https://www.cnblogs.com/skylee03/p/8081102.html
Copyright © 2011-2022 走看看