P3304 [SDOI2013]直径 树的直径

树的直径模板题,需要考虑的是第二问,求所有直径的公用边,先找出一条直径来,画图思考一下会发现,如果这条树的直径上面有个点可以找出另一条直径来,那么这个点以前的边就至少和这一条新找出的直径
不共用,那么也就是求两个端点开始最后是从哪里分叉的。从一个端点沿着直径找,直到发现延伸到另一个端点的直径,思考一下会发现这个其实就是另一个端点的最后一个分叉点,并且这个端点的延伸直径也已经找完了,如果你还能找到这个端点的分叉点,那么说明你直径找错了!!!因为还能找到就说明有更长的直径。

#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define int long long 

using namespace std;
const int maxn = 2e5 + 7;

struct node
{
    int next, to, val;
};

node edge[maxn<<1];
int vis[maxn], dis[maxn], num[maxn], head[maxn], f[maxn], deep[maxn];
int tot, ans, poi;

void add(int u, int v, int w)
{
    edge[tot] = (node){head[u], v, w};
    head[u] = tot++;
}

void dfs(int x, int fa)
{
    f[x] = fa;
    if(ans < dis[x])
    {
        ans = dis[x];
        poi = x;
    }
    for(int i = head[x]; ~i; i = edge[i].next)
    {
        int to = edge[i].to;
        if(to == fa)
            continue;
        dis[to] = dis[x] + edge[i].val;
        dfs(to, x);
    }
}
int getpath(int u)
{
    int cnt = 0;
    while(u != 0)
    {
        vis[u] = 1;
        num[++cnt] = u;
        u = f[u];
    }
    return cnt;
}

void dfs1(int u, int fa)
{
    if(deep[u] > ans)
        ans = deep[u];
    for(int i = head[u]; ~i; i = edge[i].next)
    {
        int v  = edge[i].to;
        if(vis[v] || v == fa)
            continue;
        deep[v] = deep[u] + edge[i].val;
        dfs1(v, u);
    }
}

signed main()
{
    int n;
    scanf("%lld", &n);
    memset(head, -1, sizeof(head));
    for(int i = 1; i < n; i++)
    {
        int u, v, w;
        scanf("%lld%lld%lld", &u, &v, &w);
        add(u, v, w);
        add(v, u, w);
    }
    int p, q;
    ans = 0;
    dis[1] = 0;
    dfs(1, 0);
    p = poi;
    ans = 0;
    dis[p] = 0;
    dfs(p, 0);
    int len = ans;
    q = poi;
    int l = getpath(q);
    int r = 1;
    int m = l;
    for(int i = m; i >= 1; i--)
    {
        ans = 0;
        dfs1(num[i], 0);
        if(!ans)
            continue;
        if(ans == dis[num[i]])
            l = i;
        else if(ans == len - dis[num[i]])
        {
            r = i;
            break;
        }
    }
    printf("%lld\n", len);
    printf("%lld\n", l - r);
    return 0;
}
发布了40 篇原创文章 · 获赞 13 · 访问量 844

猜你喜欢

转载自blog.csdn.net/weixin_43891021/article/details/102990428