Luogu P3304[SDOI2013]直径

Posted qihoo360

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu P3304[SDOI2013]直径相关的知识,希望对你有一定的参考价值。

题目链接
题意,求一棵树被所有直径经过的边的条数。
这题是我们8.25KS图论的最后一题,当时我果断打了暴力求所有直径然后树上差分统计的方法,好像有点小问题,boom0了。
考完改这题,改了好久,各种各样的小bug,至少有七八个。。。
思路:先随便找一条直径,然后从一个端点开始遍历这条直径,如果当前点能分叉出一条直径,那么这条直径后面的点都不可能被所有直径穿过了,于是我们找到第一个能分叉的点,然后再从这个点往回遍历,找到第一个能分叉的点,这2个点中间的路径的边即为所求。
代码就算了吧,打这题时我就没想过要有可读性

#include <cstdio>
#include <algorithm>
#include <queue>
using namespace std;
#define INF 2147483647
#define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
#define Close fclose(stdin); fclose(stdout);
const int MAXN = 200010;
inline int read(){
    int s = 0, w = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }
    return s * w;
}
struct Edge{
    int next, to, dis;
}e[MAXN << 1];
int num, head[MAXN], flag[MAXN];
inline void Add(int from, int to, int dis){
    e[++num] = (Edge){ head[from], to, dis };
    head[from] = num;
}
int pre[MAXN], in[MAXN];
int n, ans, Maxu, ans1;
long long Max;
void dfs(int u, int fa, long long dep){
    if(dep > Max) Max = dep, Maxu = u;
    for(int i = head[u]; i; i = e[i].next)
       if(e[i].to != fa)
         dfs(e[i].to, u, dep + e[i].dis);
}
void DFS(int u, int fa, long long dep){
    pre[u] = fa;
    if(dep > Max) Max = dep, Maxu = u;
    for(int i = head[u]; i; i = e[i].next)
       if(e[i].to != fa)
         DFS(e[i].to, u, dep + e[i].dis);
}
bool existOther(int u, int fa, long long dep){
    if(dep == Max) return true;
    for(int i = head[u]; i; i = e[i].next)
       if(e[i].to != fa)
         if(existOther(e[i].to, u, dep + e[i].dis)) return true;
    return false;
}
int A, B, C;
int main(){
    Open("diameter");
    n = read();
    for(int i = 1; i < n; ++i){
       A = read(); B = read(); C = read();
       Add(A, B, C); Add(B, A, C);
    }
    Max = -1; dfs(1, 0, 0);
    Max = -1; DFS(Maxu, 0, 0);
    int now = Maxu, o = 0, fa = 0, Plus = 0;
    long long deep = 0;
    while(now) flag[now] = 1, now = pre[now];
    for(int i = 1; i <= n; ++i) if(!flag[i]) pre[i] = 0;
    now = Maxu;
    while(now){
      Plus = 0;
      for(int i = head[now]; i; i = e[i].next)
         if(e[i].to != pre[now] && e[i].to != fa){
           if(existOther(e[i].to, now, deep + e[i].dis)){
             o = now;
             break;
           }
         }
         else if(e[i].to == pre[now]) Plus = e[i].dis;
      if(!o && !pre[now]) o = now;
      if(o) break;
      fa = now;
      now = pre[now];
      deep += Plus;
    }                           //找到第一个分叉的点
        ans = 0;       //往回遍历
        now = o;
        fa = pre[now];
        deep = Max - deep;
        while(now != Maxu){
          int nxt;
          ++ans;
          for(int i = head[now]; i; i = e[i].next)
             if(pre[e[i].to] != now && e[i].to != fa){
               if(existOther(e[i].to, now, deep + e[i].dis)){
                 printf("%I64d
%d
", Max, ans - 1);
                 //system("pause");
                 return 0;
               }
             }
             else if(pre[e[i].to] == now) nxt = e[i].to, Plus = e[i].dis;
          fa = now;
          now = nxt;
          deep += Plus;
        }
    printf("%I64d
%d
", Max, ans);  //如果都不能分叉
    Close;
    //system("pause");
    return 0;
}

以上是关于Luogu P3304[SDOI2013]直径的主要内容,如果未能解决你的问题,请参考以下文章

SDOI2013 直径(树的直径必经边)

3124: [Sdoi2013]直径

[SDOI2013]直径(树的直径)

[树的直径] SDOI2013 直径

[Sdoi2013]直径(树的直径)

[SDOI2013]直径 (树的直径,贪心)