• 题解 CF1336A 【Linova and Kingdom】


    题意

    给定一棵 (n) 个点的有根树(根是 (1)),让你选出 (k)个点打上标记,求出每个点到 (1) 的路径上有多少没被标记的点,让你最大化这个值。

    题解

    这道题显然可以用贪心来想。

    我们考虑一个点 (u) 的贡献。

    首先如果我们要选 (u) 那么它的子树内的所有点应该都已经被选,否则选那个没被选的点一定更优。

    同理从 (1->u) 的路径上的点一定没有被选。

    (dep_u) 代表 (u) 的深度((dep_1=0)),那么如果选 (u) 则值肯定会增加 (dep_u)

    那么会减少几个呢?

    因为选 (u) 之前 (u) 的后代一定已经被选了,所以选一个 (u) 使得它的后代到 (1) 的路径上没被选的点都减了 (1)(减掉的也就是 (u) 点)。

    (sz_u) 代表 (u) 的子树大小,则它的后代共有 (sz_u-1) 个,选 (u) 减少的值也就是 (sz_u-1)

    综上选 (u) 的代价是 (dep_u - sz_u + 1),按这个值从小到大排序,取前 (k) 个即可。

    显然这样排序一定满足上述性质。

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <queue>
    using namespace std;
    typedef long long ll;
    const int N = 2e5 + 10;
    struct node{
    	int pre, to;
    }edge[N << 1];
    int head[N], tot;
    int n, k;
    int rk[N];
    ll dep[N], sz[N], ans;
    void add(int u, int v) {
    	edge[++tot] = node{head[u], v};
    	head[u] = tot;
    }
    void dfs(int x, int fa) {
    	sz[x] = 1;
    	for (int i = head[x]; i; i = edge[i].pre) {
    		int y = edge[i].to;
    		if (y == fa) continue;
    		dep[y] = dep[x] + 1;
    		dfs(y, x);
    		sz[x] += sz[y];
    	}
    }
    bool cmp(int a, int b) {
    	return dep[a] - sz[a] + 1 > dep[b] - sz[b] + 1;
    }
    int main() {
    	scanf("%d%d", &n, &k);
    	for (int i = 1, a, b; i < n; i++) {
    		scanf("%d%d", &a, &b);
    		add(a, b);
    		add(b, a);
    	}
    	dfs(1, 0);
    	for (int i = 1; i <= n; i++) rk[i] = i;
    	sort(rk + 1, rk + n + 1, cmp);
    	for (int i = 1; i <= k; i++) {
    		int x = rk[i];
    		ans += dep[x] - sz[x] + 1;
    	}
    	printf("%lld", ans);
    	return 0;
    }
    
  • 相关阅读:
    省市区三级联动
    VUE项目PC端实现自适应rem
    (课堂笔记)第十三章GLSB涉及负载均衡算法
    LTM理解及配置笔记记录
    实验演示---GSLB部分(DC1)
    F5实验模拟拓扑
    (课堂笔记)第十三章:DNS 全局站点
    AbstractList类_Iterator内部类
    Oracle 时间格式化异常:无效数字
    Maven库镜像
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/14897348.html
Copyright © 2020-2023  润新知