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

    传送门:>HERE<

    题意:给出一颗树,求出被所有的直径都经过的边的数量

    解题思路:

      先求出任意一条直径并记录节点。

      然后依次枚举直径上的每一个节点,判断从当前节点延伸出去的非直径的一条路径的最大值,如果这一条链的长度与它所分割出来的直径的两半中的任何一半的长度相等,则即为分叉。分叉的部分由于都是直径,必然不是每条直径都会经过的,所以这两段内的边一定不会属于答案。更新一下边界就可以了。由于直径上的点每个只被访问了一遍,并且延伸出去的也最多只被访问一次(想一想,为什么),所以均摊O(n)

    Code

      注意,不能向我一样在扫的时候还O(n)求一遍最大值,这样复杂度就是接近O(n^2)了。在dfs的过程打擂就好了

    /*by DennyQi*/
    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #define  r  read()
    #define  Max(a,b)  (((a)>(b))?(a):(b))
    #define  Min(a,b)  (((a)<(b))?(a):(b))
    using namespace std;
    typedef long long ll;
    #define int long long
    const int MAXN = 200010;
    const int INF = 0x3f3f3f3f;
    const int MOD = 998244353;
    inline int read(){
        int x = 0; int w = 1; register unsigned char c = getchar();
        for(; c^'-' && (c < '0' || c > '9'); c = getchar());
        if(c == '-') w = -1, c = getchar();
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0';
        return x * w;
    }
    int N,a,b,c,P,Q,_max,L,R,flg;
    int first[MAXN*2],next[MAXN*2],to[MAXN*2],cost[MAXN*2],num_edge;
    int d[MAXN],pre[MAXN],wei[MAXN],vis[MAXN],rad[MAXN],Dist[MAXN];
    queue <int> q;
    inline void add(int u, int v, int w){
        to[++num_edge] = v;
        cost[num_edge] = w;
        next[num_edge] = first[u];
        first[u] = num_edge;
    }
    inline void BFS(int s){
        memset(d,0x3f,sizeof(d));
        d[s] = 0;
        q.push(s);
        vis[s] = 1;
        int u,v;
        while(!q.empty()){
            u = q.front();q.pop();
            for(int i = first[u]; i; i = next[i]){
                v = to[i];
                if(!vis[v]){
                    d[v] = d[u] + cost[i];
                    vis[v] = 1;
                    q.push(v);
                    pre[v] = u;
                    wei[v] = cost[i];
                }
            }
        }
    }
    void DFS(int x, int fa, int tot){
        _max = Max(_max, tot);
        int v;
        for(int i = first[x]; i != 0; i = next[i]){
            v = to[i];
            if((v != fa) && (!rad[v])){
                flg = 1;
                DFS(v, x, tot + cost[i]);
            } 
        }
    }
    main(){
        N=r;
        for(int i = 1; i < N; ++i){
            a=r,b=r,c=r;
            add(a,b,c),add(b,a,c);
        }
        BFS(1);
        for(int i = 1; i <= N; ++i) if(d[i] > _max) _max = d[i],P = i;
        memset(vis,0,sizeof(vis));
        BFS(P);
        _max = 0;
        for(int i = 1; i <= N; ++i) if(d[i] > _max) _max = d[i], Q = i;
        printf("%lld
    ", d[Q]);
        int x=P,y=Q;
        while(y != x) rad[y] = 1, y = pre[y];
        rad[P] = 1, rad[Q] = 1;
        x=P,y=Q;
        int dis = d[Q];
        L = Q, R = P;
        while(y != x){
            flg = 0;
            _max = -1;
            DFS(y, 0, 0);
            if(!flg) _max = -1;
            if(_max != -1){
                if(_max == dis){ R = y; break; }
                if(_max == d[Q] - dis) L = y;
            }
            dis -= wei[y];
            y = pre[y];
        }
        y = L;
        int ans = 0;
        while(y != R) ++ans, y = pre[y];
        printf("%lld", ans);
        return 0;
    }
  • 相关阅读:
    2018-2019-1 20165304 《信息安全系统设计基础》第六周学习总结
    2018-2019-1 20165301 20165304 20165314 实验二 固件程序设计
    2018-2019-1 20165304 《信息安全系统设计基础》第五周学习总结
    2018-2019-1 20165304 《信息安全系统设计基础》第四周学习总结
    构建之法读后感
    20165304 2017-2018-2《Java程序设计》学习总结
    20165304实验五 网络编程与安全
    2018-2019-1 20165324《信息安全系统设计基础》实验五
    2018-2019-1 20165324 《信息安全系统设计基础》第八周课上测试
    2018-2019-1 20165324 《信息安全系统设计基础》实验四 外设驱动程序设计
  • 原文地址:https://www.cnblogs.com/qixingzhi/p/9389160.html
Copyright © 2011-2022 走看看