Educational Codeforces Round 74 F. The Maximum Subtree (换根dp)

题目链接

题目大意:

给点分配区间,如果两个点的区间相交,则两个点之间有边相连,否则没有。给你一棵树,求一棵最大的子树使得可以通过给点分配区间来得到这颗树。(n<=3e5)

解题思路:

画一画可以发现,一棵树合法,它的根结点可以有两个儿子向下生长,而每个非根结点只能有一个儿子向下生长:
Educational Codeforces Round 74 F. The Maximum Subtree (换根dp)_第1张图片
这样就可以dp了,dp[u][0/1]表示u选一个儿子生长能得到的最多/次多结点,这样可以得到根节点的答案 = d p [ r o o t ] [ 0 ] + d p [ r o o t ] [ 1 ] − s z [ r o o t ] + 1 =dp[root][0]+dp[root][1]-sz[root]+1 =dp[root][0]+dp[root][1]sz[root]+1
然后通过换根dp获得每个结点作为根时的答案。
换根dp要判断一下它父亲f的dp[f][0]是否由当前结点转移而来。

#include
#define ll long long
using namespace std;
const int maxn = 3e5 + 50;
vector<int> g[maxn];
int sz[maxn], dp[maxn][2], ans[maxn];
int n;
void init(){
    scanf("%d", &n); for(int i = 1; i <= n; ++i) g[i].clear();
    for(int i = 1; i < n; ++i) {
        int u, v; scanf("%d%d", &u, &v);
        g[u].push_back(v); g[v].push_back(u);
    }
}
void dfs(int u, int f){
    sz[u] = g[u].size();
    if(u != 1) sz[u]--;
    dp[u][0] = dp[u][1] = sz[u];
    for(int i = 0; i < g[u].size(); ++i){
        int v = g[u][i];
        if(v == f) continue;
        dfs(v, u);
        int t = dp[v][0]+sz[u];
        if(dp[u][0] < t){
            dp[u][1] = dp[u][0];
            dp[u][0] = t;
        }
        else if(dp[u][1] < t) dp[u][1] = t;
    }
}
void DFS(int u, int f){
    if(u != 1) dp[u][0]++, dp[u][1]++;
    if( (dp[u][0]-1+sz[f] + (f != 1) ) != dp[f][0]){
        //cout<<"u:"<
        int t = dp[f][0]-1+sz[u]+(u!=1);
        if(dp[u][0] < t){
            dp[u][1] = dp[u][0];
            dp[u][0] = t;
        }
        else if(dp[u][1] < t) dp[u][1] = t;
    }
    else{
        int t = dp[f][1]-1+sz[u]+(u!=1);
        if(dp[u][0] < t){
            dp[u][1] = dp[u][0];
            dp[u][0] = t;
        }
        else if(dp[u][1] < t) dp[u][1] = t;
    }
    ans[u] = dp[u][0] + dp[u][1] - g[u].size() + 1;
    for(int i = 0; i < g[u].size(); ++i){
        int v = g[u][i];
        if(v == f) continue;
        DFS(v, u);
    }
}
void sol(){
    dfs(1, 1);
    //ans[1] = dp[1][0] + dp[1][1] - sz[1] + 1;
    DFS(1, 0);
    int mx = 0;
    for(int i = 1; i <= n; ++i) {
        //cout<<"i:"<
        mx = max(mx, ans[i]);
    }
    printf("%d\n", mx);
}
int main()
{
	int T; cin>>T;
	while(T--){
        init(); sol();
	}
}

你可能感兴趣的:(dp)