Codeforces 1238F. The Maximum Subtree

传送门

考虑构造一些区间使得树尽可能的 "大"

发现这棵树最多就是一条链加上链上出去的其他边连接的点

构造的区间大概长这样(图比较丑请谅解..$qwq$,图中每一个 "└┘" 都是一段区间):

 

发现树其实就是个 "毛毛虫":传送门

所以直接求最大的毛毛虫即可

设毛毛虫的主链集合为 $S$ ,那么毛毛虫的点数就是 $\sum_{u \in S} (du[u])-(size-2)$

其中 $du[u]$ 表示点 $u$ 的度数,$size$ 为 $S$ 的点集大小,$-(size-2)$ 是因为除了主链两端的两点以外主链其他点都被算了两次

那么化一下即为 $\sum_{u \in S}(du[u]-1)+2$ 直接求树的带权直径即可

注意这个式子是在主链有两个端点的情况下成立的,所以对于只有一个点的情况要特判

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=3e5+7;
int Q,n,val[N];
int fir[N],from[N<<1],to[N<<1],cntt;
inline void add(int a,int b) { from[++cntt]=fir[a]; fir[a]=cntt; to[cntt]=b; }
int mx,p;
void dfs(int x,int fa,int dis)
{
    if(dis>mx) mx=dis,p=x;
    for(int i=fir[x];i;i=from[i])
        if(to[i]!=fa)
            dfs(to[i],x, dis + val[to[i]] );
}
int main()
{
    Q=read();
    while(Q--)
    {
        n=read(); int a,b;
        if(n==1) { printf("1\n"); continue; }
        for(int i=1;i<=n;i++)
            fir[i]=0,val[i]=-1;
        cntt=p=0; mx=-1;
        for(int i=1;i<n;i++)
        {
            a=read(),b=read();
            add(a,b); add(b,a);
            val[a]++; val[b]++;
        }
        dfs(1,0,val[1]); mx=-1; dfs(p,0,val[p]);
        printf("%d\n",mx+2);
    }
    return 0;
}

 

posted @ 2019-10-09 17:36  LLTYYC  阅读(460)  评论(0编辑  收藏  举报