题目大意:给你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 */