zoukankan      html  css  js  c++  java
  • BZOJ3124 直径

    Description:

    求树的直径的必须边

    思路:求出任意一条直径,然后对这条直径的每个点进行DFS(不过直径任何点),定义一个l,r,初始为直径的两端,然后计算出该点能到的最远距离如果等于其左端或右端,那么l = pos 或者 r = pos。

    注意因为是从右向左搜的,所以左边的点只要收一次,且越早越好。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int N = 1e6 + 10;
    
    int head[N], now = 1;
    struct edges{
        int to, next, w;
    }edge[N<<1];
    void add(int u, int v, int w){ edge[++now] = {v, head[u], w}; head[u] = now;}
    
    int n, m, pre[N], tot, pos1, pos2;
    bool isd[N];
    long long dep[N], mx;
    void dfs1(int x){
        for(int i = head[x]; i; i = edge[i].next){
            int v = edge[i].to;
            if(pre[x] == v) continue;
            pre[v] = x;
            dep[v] = dep[x] + edge[i].w;
            dfs1(v);
        }
    }
    void dfs(int x, int fa){
        for(int i = head[x]; i; i = edge[i].next){
            int v = edge[i].to;
            if(v == fa || isd[v]) continue;
            dep[v] = dep[x] + edge[i].w;
            mx = max(dep[v], mx);
            dfs(v, x);
        }
    }
    int main(){
        scanf("%d", &n);
        for(int i = 1; i < n; i++){
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            add(x, y, z); add(y, x, z);
        }
        dfs1(1);
        mx = 0;
        for(int i = 1; i <= n; i++)
          if(dep[i] > mx) mx = dep[i], pos1 = i;
        memset(dep, 0, sizeof(dep));
        memset(pre, 0, sizeof(pre));
        dfs1(pos1);
        mx = 0;
        for(int i = 1; i <= n; i++)
          if(dep[i] > mx) mx = dep[i], pos2 = i;
        for(int i = pos2; i; i = pre[i])
          isd[i] = 1;
        bool flag = 0;
        int l = pos1, r = pos2;
        long long ans = dep[pos2] - dep[pos1];
        for(int i = pre[pos2]; i != pos1; i = pre[i]){
            dfs(i, -1);
            int ls = dep[i], rs = dep[pos2] - dep[i];
            dep[i] = mx = 0;
            dfs(i, -1);
            if(mx == rs) r = i;
            if(mx == ls && !flag) 
              flag = 1, l = i;
        }
        for(int i = r; i != l; i = pre[i]) tot++; 
        printf("%lld
    %d
    ",ans, tot);
        return 0;
    }
    View Code
  • 相关阅读:
    玩转Visual Studio Editor篇
    .Net2.0的集合操作 What i know?
    Log文件压缩
    [转]比较高效地实现从两个不同数组中提取相同部分组成新的数组(只支持Int类型) [C#]
    Stream 和 Byte[]互操作
    net 2.0 中如何在线程引发的事件中控制forms controls
    C# 操作Word文档(转)
    利用Lucene.net搜索引擎进行多条件搜索的做法
    c# 添加图片水印,可以指定水印位置+生成缩略图
    SDN第一次作业
  • 原文地址:https://www.cnblogs.com/Rorshach/p/8724829.html
Copyright © 2011-2022 走看看