The Maximum Subtree

原题链接:https://codeforces.com/contest/1238/problem/F

分析这道题,构造出最后这棵树的形状是一条主链,链上每个结点可以带叶子结点(在原树中可能不是叶子结点),那么答案就是主链上每个点的度之和再减主链节点数-2,因为中间的结点被重复计算了,转换为:\sum \left ( d(u_) -1\right ) + 2  u

是主链上的结点,于是题目转化为树上带权直径;

树上直径可以通过两次bfs或者dfs找直径两个端点。也可以通过树上dp,对每个结点维护最大值和次大值(子树最远距离)

代码采用dfs

#include
using namespace std;
const int maxn = 300000 + 10;
int head[maxn];
struct node
{
    int to, next;
}edges[maxn * 2];
int cnt, du[maxn], n;
void addedges(int u, int v)
{
    edges[cnt++] = {v, head[u]};head[u] = cnt - 1;
}

void init()
{
    cnt = 0;
    memset(head, -1, sizeof(int) * (n + 1));
    memset(du, 0, sizeof(int) * (n + 1));
}
int e, maxd;
void dfs(int u, int sum, int fa)
{
    sum += du[u] - 1;
    if(sum > maxd)maxd = sum, e = u;
    for(int i = head[u]; i != -1;i = edges[i].next)
    {
        if(edges[i].to == fa)continue;
        dfs(edges[i].to, sum, u);
    }
}
int main()
{
    int q; scanf("%d", &q);
    while(q--)
    {
        scanf("%d", &n);
        init();
        for(int i = 0, u, v; i < n -1 ; ++i)
        {
            scanf("%d%d", &u, &v);
            addedges(u, v); addedges(v, u);
            du[u]++, du[v]++;
        }
        if(n == 1){cout << 1 << endl;continue;}
        int u = 1;
        maxd = -1;
        dfs(u, 0, 0);
        dfs(e, 0, 0);
        printf("%d\n", maxd + 2);
    }
    return 0;
}

 

你可能感兴趣的:(The Maximum Subtree)