1 条题解

  • 0
    @ 2026-5-2 13:09:15

    考虑没有边权和限制时怎么做。

    fx,if_{x,i} 表示点 xx 上连了 i\le i 条边时,xx 的子树中最多能被选择的边数。儿子转移到父亲时考虑此边是否选择即可:

    $$f_{x,i}=\max_{y\in son_x}(f_{x,i}+f_{y,k},f_{x,i-1}+f_{y,k-1}+1)$$

    考虑加入边权和的限制。当一条边 xyx\rightarrow y 被选择时,此边会给总边权和带来 wx,yw_{x,y} 的贡献。那么用 fx,if_{x,i} 记录一个二元组 (a,b)(a,b) 表示答案。

    定义广义加法:

    (a,b)+(c,d)=(a+c,b+d)(a,b)+(c,d)=(a+c,b+d)

    定义广义 max\max

    $$\max((a,b),(c,d))=\begin{cases} (a,\min(b,d))&\text{if }a=c\\ (a,b)&\text{if }a>c\\ (c,d)&\text{if }a<c \end{cases}$$

    转移:

    $$f_{x,i}=\max_{y\in son_x}(f_{x,i}+f_{y,k},f_{x,i-1}+f_{y,k-1}+(1,w_{x,y}))$$

    这样就足以通过本题。但空间上还可以继续优化。观察转移,发现只有 fy,k1,fy,kf_{y,k-1},f_{y,k} 被用到,考虑把状态改为 fx,0/1f_{x,0/1} 表示点 xx 上连了 k1/kk-1/k 条边时,xx 的子树的答案。同时再记一个临时数组 FiF_{i} 表示当前点 xxfx,if_{x,i}

    转移就可以变为:

    $$F_{i}=\max_{y\in son_x}(F_{i}+f_{y,1},F_{i-1}+f_{y,0}+(1,w_{x,y}))$$

    转移完后记得把 Fk1,FkF_{k-1},F_{k} 赋值给 fx,0/1f_{x,0/1}

    #include <bits/stdc++.h>
    #define LL long long
    #define PII pair <int, int>
    using namespace std;
    const int maxn = 1e5 + 10;
    int n, k, fa[maxn], w[maxn];
    vector <PII> G[maxn];
    struct info {
    	LL siz, sum;
    	friend info operator + (info x, info y) {
    		return {x.siz + y.siz, x.sum + y.sum};
    	}
    }f[maxn][2], F[110];
    info max(info x, info y) {
    	if(x.siz == y.siz) return {x.siz, min(x.sum, y.sum)};
    	else if(x.siz > y.siz) return x;
    	else return y;
    }
    void dfs(int x) {
    	for(auto tmp : G[x]) {
    		int y = tmp.first, z = tmp.second;
    		dfs(y);
    	}
    	for(int i = 0; i <= k; i++) F[i] = {0, 0};
    	for(auto tmp : G[x]) {
    		int y = tmp.first, z = tmp.second;
    		for(int i = k; i >= 0; i--) {
    			F[i] = F[i] + f[y][1];
    			if(i >= 1) F[i] = max(F[i], F[i - 1] + f[y][0] + (info){1, z});
    		}
    	}
    	f[x][0] = F[k - 1], f[x][1] = F[k];
    }
    int main() {
    	scanf("%d%d", &n, &k);
    	for(int i = 2; i <= n; i++) {
    		scanf("%d%d", &fa[i], &w[i]);
    		G[fa[i]].push_back({i, w[i]});
    	}
    	dfs(1);
    	printf("%lld %lld\n", f[1][1].siz, f[1][1].sum);
    	return 0;
    }
    
    
    • 1

    [ROIR 2022] 网络系统升级计划 (Day 2)

    信息

    ID
    10296
    时间
    1000ms
    内存
    512MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者