[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;
}
原文地址:https://www.cnblogs.com/qixingzhi/p/9389160.html