CF980E The Number Games

给定一棵大小为 \(n\) 的树,第 \(i\) 个点的点权为 \(2^i\) ,删掉 \(k\) 个点及其连边,使得剩下的点组成一个连通块,且权值和最大,输出要删掉的点

\(n,\ k\leq10^6\)

贪心,倍增,dfs序


很容易想到一个贪心:不断删掉能被删除且权值最小的点,用堆实现

但很明显这是错的:局部最优 \(\neq\) 全局最优

因为点权为 \(2^i\) ,所以与其选择 \(1,\ 2,\ \cdots,\ i-1\) 不如选 \(i\) 这一个点

考虑这样一个 \(O(n^2)\) 贪心:从大往小确定不被删的点。以 \(n\) 为根,若当前枚举到的节点可选则将根到这个点的路径上的所有点都选掉

可以发现,问题转化为了快速求出一个点是否可选,并标记路径

因为最多会标记 \(n-1\) 条路径,所以可以暴力标记,倍增查询

时间复杂度 \(O(n\log n)\) ,空间复杂度 \(O(n\log n)\)

原操作还有另一种实现方式:树状数组维护dfs序上每个点的距离,标记路径时修改子树内答案

这种做法虽然略显繁琐,但是不失为一种常用的高效算法

时间复杂度 \(O(n\log n)\) ,空间复杂度 \(O(n)\)

倍增代码

#include <bits/stdc++.h>
using namespace std; const int maxn = 1e6 + 10;
int n, k, fa[21][maxn]; bool vis[maxn];
vector <int> e[maxn]; void dfs(int u, int f) {
fa[0][u] = f;
for (int i = 1; i < 21; i++) {
fa[i][u] = fa[i - 1][fa[i - 1][u]];
}
for (int v : e[u]) {
if (v != f) dfs(v, u);
}
} int lca(int u) {
int res = 0;
for (int i = 20; ~i; i--) {
if (!vis[fa[i][u]]) {
u = fa[i][u], res |= 1 << i;
}
}
return res;
} int main() {
scanf("%d %d", &n, &k);
for (int i = 1, u, v; i < n; i++) {
scanf("%d %d", &u, &v);
e[u].push_back(v), e[v].push_back(u);
}
dfs(n, 0), vis[0] = 1;
int tmp = n - k;
for (int i = n; i; i--) {
int t = lca(i);
if (t < tmp) {
int cur = i;
while (!vis[cur]) {
vis[cur] = 1, tmp--, cur = fa[0][cur];
}
}
}
for (int i = 1; i < n; i++) {
if (!vis[i]) printf("%d ", i);
}
return 0;
}

dfs序+树状数组代码

#include <bits/stdc++.h>
using namespace std; const int maxn = 1e6 + 10;
int n, k, now, a[maxn], c[maxn], sz[maxn], fa[maxn], tid[maxn], dep[maxn]; bool vis[maxn];
vector <int> e[maxn]; void upd(int pos, int x) {
for (; pos <= n; pos += pos & -pos) {
c[pos] += x;
}
} int query(int pos) {
int res = 0;
for (; pos; pos &= pos - 1) {
res += c[pos];
}
return res;
} int dfs(int u, int f) {
a[++now] = u, tid[u] = now, fa[u] = f, dep[u] = dep[f] + 1;
for (int v : e[u]) {
if (v != f) sz[u] += dfs(v, u);
}
return ++sz[u];
} int main() {
scanf("%d %d", &n, &k);
for (int i = 1, u, v; i < n; i++) {
scanf("%d %d", &u, &v);
e[u].push_back(v), e[v].push_back(u);
}
dfs(n, 0), upd(1, -1);
for (int i = 1; i <= n; i++) {
upd(i, dep[a[i]] - dep[a[i - 1]]);
}
int tmp = n - k; vis[0] = 1;
for (int i = n; i; i--) {
if (query(tid[i]) < tmp) {
for (int cur = i; !vis[cur]; tmp--, vis[cur] = 1, cur = fa[cur]) {
upd(tid[cur], -1), upd(tid[cur] + sz[cur], 1);
}
}
}
for (int i = 1; i < n; i++) {
if (!vis[i]) printf("%d ", i);
}
return 0;
}

CF980E The Number Games的更多相关文章

  1. CF980E The Number Games【树链剖分/线段树】

    CF980E The Number Games 题意翻译 Panel 国将举办名为数字游戏的年度表演.每个省派出一名选手. 国家有 n 个编号从 1 到 n 的省,每个省刚好有一条路径将其与其他省相连 ...

  2. Codeforces 980 E. The Number Games

    \(>Codeforces \space 980 E. The Number Games<\) 题目大意 : 有一棵点数为 \(n\) 的数,第 \(i\) 个点的点权是 \(2^i\) ...

  3. Codeforces 980E The Number Games 贪心 倍增表

    原文链接https://www.cnblogs.com/zhouzhendong/p/9074226.html 题目传送门 - Codeforces 980E 题意 $\rm Codeforces$ ...

  4. codeforces 980E The Number Games

    题意: 给出一棵树,要求去掉k个点,使得剩下的还是一棵树,并且要求Σ(2^i)最大,i是剩下的节点的编号. 思路: 要使得剩下的点的2的幂的和最大,那么肯定要保住大的点,这是贪心. 考虑去掉哪些点的话 ...

  5. Codeforces 980E The Number Games - 贪心 - 树状数组

    题目传送门 传送点I 传送点II 传送点III 题目大意 给定一颗有$n$个点的树,$i$号点的权值是$2^{i}$要求删去$k$个点,使得剩下的点仍然连通,并且总权值和最大,问删去的所有点的编号. ...

  6. Codeforces Round #480 (Div. 2) E - The Number Games

    题目大意:给你n个点的一棵树, 每个点的权值为2^i ,让你删掉k个点使得剩下的权值和最大. 思路:这题还是比较好想的, 我们反过来考虑, 剩下一个的情况肯定是选第n个点,剩下两个 我们肯定优先考虑第 ...

  7. The Number Games CodeForces - 980E (树, 贪心)

    链接 大意: 给定$n$节点树, 求删除$k$个节点, 使得删除后还为树, 且剩余点$\sum{2^i}$尽量大 维护一个集合$S$, 每次尽量添加最大的点即可 这样的话需要支持求点到集合的最短距离, ...

  8. cf round 480E The Number Games

    题意:给一棵树,点$i$的点权是$2^i$,你需要删掉$k$个点,使得剩下的点连通的情况下剩下的点权值和最大. $k \leq n \leq 10^6$ 如果考虑删哪些点,是不好考虑的,会出问题. 反 ...

  9. POJ1336 The K-League[最大流 公平分配问题]

    The K-League Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 715   Accepted: 251 Descri ...

随机推荐

  1. css3 简易时钟

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  2. es6 语法 (数值扩展)

    { //二进制数值都是0b开头,八进制0o console.log(0b111110111) console.log(0o767); } { console.log('15',Number.isFin ...

  3. POJ 2942Knights of the Round Table(tarjan求点双+二分图染色)

    Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 13954   Accepted: 4673 Description Bein ...

  4. WPF控件库:文字按钮的封装

    需求:封装按钮,按钮上面只显示文字.在鼠标移上去.鼠标点击按钮.以及将按钮设为不可用时按钮的背景色和前景色需要发生变化 实现:继承Button类,封装如下6个属性: #region 依赖属性 /// ...

  5. (网页)table加上分页,优点可随便加样式

    1.先有静态的页面: <div class="col-xs-12"> <table id="tbtablesaleinfo" class=&q ...

  6. codeforces 632C The Smallest String Concatenation

    The Smallest String Concatenation 题目链接:http://codeforces.com/problemset/problem/632/C ——每天在线,欢迎留言谈论. ...

  7. 原型模式ProtoType

    #!/usr/bin/env python # -*- coding: utf-8 -*- # @Time : 2019/3/4 21:49 # @Author : ChenAdong # @emai ...

  8. CentOS7中启动Tomcat后,8080端口不能被外部访问的解决办法。

    运行:/sbin/iptables -I INPUT -p tcp --dport 8080 -j ACCEPT

  9. Mybatis 学习---${ }与#{ }获取输入参数的区别、Foreach的用法

    一.Mybatis中用#{}和${}获取输入参数的区别 1.“#{}“和“${}”都可以从接口输入中的map对象或者pojo对象中获取输入的参数值.例如 <mapper namespace=&q ...

  10. 两个Map的对比,三种方法,将对比结果写入文件。

    三种方法的思维都是遍历一个map的Key,然后2个Map分别取这2个Key值所得到的Value. #第一种用entry private void compareMap(Map<String, S ...