当前位置 博文首页 > 平凡人Kalzn的博客:小a与欧拉回路(树的直径的求法)

    平凡人Kalzn的博客:小a与欧拉回路(树的直径的求法)

    作者:[db:作者] 时间:2021-09-21 21:05

    树的直径的求法-小a与欧拉回路

    题目链接
    这道题是一点思路都没有,看了别人的题解后,知道了答案其实是

    ans = 树的总权值 * 2 - 树的直径;

    首先,易知每个边最多复制两遍。思考后,可知,我们先假定每个边都复制了两遍,于是得到

    树的总权值 * 2;

    显然,我们算多了。于是我们考虑减去某些边,这里我们可以将树看作一个带有支路的一条主干道
    这时我们从主干道的一端出发,到达另一端。那么此时主干道上的边可以只复制一次,而支路上的边要复制两次。所以,我们只要让这条“主干道”最长就好了,即为树的直径。于是就有上文的结论。

    这里使用两次bfs求直径。

    第一次:以任意点为起点,bfs出离当前点最远的一点point
    第二次:以point为起点, bfs出离point最远的点的距离,该距离即为所求

    下面是ac代码:

    #include <iostream>
    #include <cstring>
    #include <queue>
    #define ll long long
    using namespace std;
    const int MAX = 2000005;
    int ver[2*MAX] = { 0 }, he[2*MAX] = { 0 }, ne[2*MAX] = { 0 };
    int e[MAX] = { 0 };
    bool vis[MAX] = { 0 };
    ll dis[MAX] = { 0 };
    int tot = 0;
    int n;
    void init()
    {
        tot = 0;
        memset(e, 0, sizeof(e));
        memset(ver, 0, sizeof(ver));
        memset(he, 0, sizeof(he));
        memset(ne, 0, sizeof(ne));
    }
    void add(int x, int y, int w)
    {
        ver[++tot] = y;
        e[tot] = w;
        ne[tot] = he[x];
        he[x] = tot;
    }
    ll len = 0, point;
    void bfs(int st)
    {
        queue<int> q;
        while(q.size()) q.pop();
        memset(vis, 0, sizeof(vis));
        memset(dis, 0, sizeof(dis));
        vis[st] = 1;
        q.push(st);
        while(q.size())
        {
            int te = q.front();
            q.pop();
            for (int i = he[te]; i; i = ne[i])
            {
                if (!vis[ver[i]])
                {
                    vis[ver[i]] = 1;
                    dis[ver[i]] = dis[te] + e[i];
                    if (dis[ver[i]] > len)
                    {
                        len = dis[ver[i]];
                        point = ver[i];
                    }
                    q.push(ver[i]);
                }
            }
        }
        return;
    }
    int main()
    {
        cin >> n;
        int x, y, w;
        ll ans = 0;
        for (int i = 1; i < n; i++)
        {
            scanf("%d%d%d", &x, &y, &w);
            add(x, y, w);
            add(y, x, w);
            ans += w<<1;
        }
        len = 0;
        bfs(1);
        len = 0;
        bfs(point);
        printf("%lld\n", ans - len);
        return 0;
    }
    
    
    cs