Codeforces1238F. The Maximum Subtree(树形dp)

题目链接:传送门

思路:

题意说用线段的相交作为边,来构造树,所以不存在大于等于3个的线段两两相交,否则会构成环。因而构造出的树中,每个点最多只会与2个度大于1的节点相邻。

不妨把1设为树根,用degu表示原树中节点u的度,ans表示答案。

用fu表示:假设以u为根的子树,已经有一条边连向了一个度大于1的点时,所能构成的最大的“子树的子树”的大小,则有:

f= 1,if degu=1。叶子本身就是一个点,大小为1。

fu = max{v是u的子节点 | fv} + degu-2 + 1。所有孩子中选一个fv最大的作为第2个度大于1的节点(第1个已经连出去了),这时相邻的点已经用掉2个了,剩余其他的所有相邻的点的数量为degu-2,再算上u本身。

这样处理完之后答案就很好算了。

对于一个节点u的子节点v中,fv最大的两个之和+degu-2+1,就是答案的一种可能。

(对答案的更新,代码中不是这样写的。我在更新答案的时候,利用了fu已经保存之前(fv+degu-2+1)的最大值相关信息的特点,直接用fu来更新答案了)

代码实现:O(N)

#include <bits/stdc++.h>
#define fast ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define N 300005
#define M 300005
#define INF 0x3f3f3f3f
#define mk(x) (1<<x) // be conscious if mask x exceeds int
#define sz(x) ((int)x.size())
#define upperdiv(a,b) (a/b + (a%b>0))
#define mp(a,b) make_pair(a, b)
#define endl '\n'
#define lowbit(x) (x&-x)

using namespace std;
typedef long long ll;
typedef double db;

/** fast read **/
template <typename T>
inline void read(T &x) {
    x = 0; T fg = 1; char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') fg = -1;
        ch = getchar();
    }
    while (isdigit(ch)) x = x*10+ch-'0', ch = getchar();
    x = fg * x;
}
template <typename T, typename... Args>
inline void read(T &x, Args &... args) { read(x), read(args...); }

int tot = 0;
int head[N], nxt[M<<1], ver[M<<1], deg[N];
void addEdge(int u, int v) {
    nxt[++tot] = head[u], ver[tot] = v, head[u] = tot;
    deg[u]++;
}

int f[N];
bool vis[N];
int ans;
void dfs(int u) {
    vis[u] = true;
    f[u] = deg[u];
    for (int i = head[u]; i != -1; i = nxt[i]) {
        int v = ver[i];
        if (vis[v])
            continue;
        dfs(v);
        ans = max(ans, f[u] + f[v]);
        f[u] = max(f[u], f[v] + deg[u]-2 + 1);
    }
}
int main()
{
    int q; read(q);
    while (q--) {
        int n; read(n);
        ans = 0;
        tot = 0;
        for (int i = 1; i <= n; i++) {
            head[i] = -1;
            deg[i] = 0;
            f[i] = 0;
            vis[i] = false;
        }
        int u, v;
        for (int i = 1; i <= n-1; i++) {
            read(u, v);
            addEdge(u, v);
            addEdge(v, u);
        }
        dfs(1);
        cout << ans << endl;
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Lubixiaosi-Zhaocao/p/11701465.html