Codeforces Round #480 (Div. 2) E

题目大意:给你n个点的一棵树, 每个点的权值为2^i ,让你删掉k个点使得剩下的权值和最大。

思路:这题还是比较好想的, 我们反过来考虑, 剩下一个的情况肯定是选第n个点,剩下两个

我们肯定优先考虑第n - 1 个点, 因为其他点全部加起来都没有这个点的权值大, 所以我们可以

以第n个点为根, 倍增出每个点祖先的情况, 然后从后往前贪心, 能取到就取, 不能取到就跳过。

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define fi first
 4 #define se second
 5 #define mk make_pair
 6 #define pii pair<int,int>
 7 #define piii pair<int, pair<int,int>>
 8 
 9 using namespace std;
10 
11 const int N=1e6 + 7;
12 const int M=1e4 + 7;
13 const int inf = 0x3f3f3f3f;
14 const LL INF = 0x3f3f3f3f3f3f3f3f;
15 const int mod = 1e9 + 7;
16 
17 int n, k, p[N][21];
18 vector<int> edge[N];
19 bool in[N];
20 
21 void dfs(int u, int fa) {
22     p[u][0] = fa;
23     for(int i = 1; i < 21; i++)
24         p[u][i] = p[p[u][i - 1]][i - 1];
25     for(int v : edge[u]) {
26         if(v == fa) continue;
27         dfs(v, u);
28     }
29 }
30 
31 int cal(int u, int k) {
32     for(int i = 20; i >= 0; i--) {
33         if(k >= (1 << i)) {
34             k -= 1 << i;
35             u = p[u][i];
36         }
37     }
38     return u;
39 }
40 
41 int main() {
42     scanf("%d%d", &n, &k);
43     k = n - k;
44     for(int i = 1; i < n; i++) {
45         int u, v; scanf("%d%d", &u, &v);
46         edge[u].push_back(v);
47         edge[v].push_back(u);
48     }
49     in[0] = true;
50     dfs(n, 0);
51 
52     for(int i = n; i >= 1 && k; i--) {
53         int u = cal(i, k);
54         if(in[u]) {
55             int now = i;
56             while(!in[now]) {
57                 in[now] = true;
58                 now = p[now][0];
59                 k--;
60             }
61         }
62     }
63 
64     for(int i = 1; i <= n; i++)
65         if(!in[i]) printf("%d ", i);
66     return 0;
67 }
68 /*
69 */
原文地址:https://www.cnblogs.com/CJLHY/p/9018387.html