P13680 未送出的花 [树上背包]

传送门

首先注意到一条从\(1\)节点往下的路径权值一定要是单调递减的。这样就可以算出每个节点的权值要作为多少个点的美丽值,将这个值用\(siz\)储存

接着我们发现,对于一个题目要求的\(k\),我们需要选择一些点,使得这些点深度(距离当前子树的根)之和最小(因为每多选一个点就需要多放一个数,这样最终答案就会可能更小),并且\(\sum siz\)不小于\(k\)

于是可以用树上背包,\(dp_{i,j}\)表示已\(i\)为根的子树中,\(siz\)之和为\(j\)的深度之和最小为多少,直接dfs对每个节点转移的复杂度是\(O(n^3)\)

于是我们可以在\(dfs\)序上进行dp,\(dp_{i,j}\)表示\(i-n\)\(siz\)之和为\(j\)的深度之和最小。这样转移就变成了
$dp_{i,j} = min (dp_{i,j},dp_{i+1,j - siz_i}+1,dp_{i+l_i,j}) $
其中 \(l_i\)表示以 \(i\)为根的子树大小
这样就普通的线性背包复杂度相同
实际上,很多树上背包都可以利用dfs序将复杂度优化掉一维

#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;
const int inf = 1e9 + 10;
int n,cnt;
struct node {
    int id,w,dep;
    bool operator < (const node &a) const {
        if(w == a.w) return dep < a.dep;
        return w > a.w;
    }
};
vector<vector<int> > g,dp;
vector<int> tmp,ans,siz,l,num;

void dfs(int u,int fa) {
    num[++cnt] = u;
    l[u] = 1;
    int len = tmp.size();
    len--;
    siz[tmp[len >> 1]]++;
    for(auto i : g[u]) {
        if(i == fa) continue;
        tmp.push_back(i);
        dfs(i,u);
        l[u] += l[i];
        tmp.pop_back();
    }
}

void solve() {
    cin >> n;
    cnt = 0;
    ans.assign(n + 10,0);
    siz.assign(n + 10,0);
    num.assign(n + 10,0);
    l.assign(n + 10,0);
    tmp.clear();
    g.assign(n + 10,vector<int>());
    dp.assign(n + 10,vector<int>(n + 10,inf));
    dp[1][0] = 0;
    for(int u,v,i = 1;i < n;i++) {
        cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    tmp.push_back(1);
    dfs(1,0);
    for(int i = n;i >= 1;i--) {
        dp[i][siz[num[i]]] = 0;
        for(int j = siz[num[i]];j <= n;j++)
            dp[i][j] = min({dp[i + l[num[i]]][j],dp[i + 1][j - siz[num[i]]] + 1,dp[i][j]});
    }
    int res = inf;
    for(int i = n;i >= 1;i--) {
        res = min(res,dp[1][i]);
        ans[i] = n - res;
    }
    for(int i = 1;i <= n;i++) cout << ans[i] << ' ';
    cout << '\n';
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    int t = 1;
    cin >> t;
    while(t--) solve();
    
    return 0;
}
posted @ 2025-08-09 21:00  孤枕  阅读(8)  评论(0)    收藏  举报