树的直径变形——cf1238F

/*
题目给定一些一维线段[li,ri],要求从这些线段里挑出一些线段,每条线段对应一个点,如果两线段相交,那么点连边,这样得到的树是good-tree 
现在给定一棵树,要求从该树中选出一棵子树,使这棵子树是good-tree

显然不能有三个线段两两相交,这样就成了环
对应到good-tree的性质上,就是一个根最多连两个size>1的结点,但可以挂多个size=1的结点,非根结点最多挂一个size>1的结点
 
参照求直径的树形dp,令dp[u]表示已经连了一个size>1的儿子的最大值,当以u为根时,只要再去找另一个儿子进行匹配就可以了 
dp[u]的初始值:u连了所有儿子,这样并不影响u的一个儿子挂链,所以要预处理出u的度数 
*/
#include<bits/stdc++.h>
#include<vector>
using namespace std;
#define N 300005

vector<int>G[N];
int n,q,dp[N],ans,d[N];

void dfs(int u,int pre){
    for(auto v:G[u]){//先处理出子节点的u 
        if(v==pre)continue;
        dfs(v,u);    
    }
    
    dp[u]=d[u]-1+1;//不算pre的度数+自身 
    for(auto v:G[u]){
        if(v==pre)continue;
        ans=max(ans,dp[u]+dp[v]);
        dp[u]=max(dp[u],dp[v]+d[u]-2+1);    
    }
}

int main(){
    cin>>q;while(q--){
        cin>>n;
        for(int i=1;i<=n;i++)G[i].clear(),d[i]=0;
        for(int i=1;i<n;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            G[x].push_back(y);
            G[y].push_back(x);
            d[x]++;d[y]++;
        }
        ans=0;
        for(int i=1;i<=n;i++)dp[i]=0;
        dfs(1,1);
        cout<<ans<<'\n';
    }
}

 

posted on 2019-10-21 12:09  zsben  阅读(287)  评论(0编辑  收藏  举报

导航