zoukankan      html  css  js  c++  java
  • [CodeForces][贪心][树形结构]CF980E The Number Games

    题面

    看到树形结构我们可能会想到树形 (DP),但是仔细研究过后我们会发现这题是不需要 (DP) 的。
    观察每个点的贡献为 (2^i) ( (i) 为节点标号 ),也就是说,选择一个标号更大的点一定比选择几个标号小的点优

    这时我们贪心的思路就明朗了:
    (n - 1) 遍历每个点,被选择的点之间的路径都需要连接,只要一个点路径上需要新增的点加起来不超过限制,就加入该点 ( 以及路径上的点 )。

    至于路径,我们只需要用 (DFS) 序维护,然后用差分树状数组暴力维护一下一个点到根节点的路径长度即可

    代码:

    // 贪心的考虑:2^n 一定保留
    // DFS 暴力跳点
    
    # include <iostream>
    # include <cstdio>
    # define MAXN 1000005
    # define fa(x) nd[x].fa
    # define dep(x) nd[x].dep
    # define siz(x) nd[x].siz
    # define dfn(x) nd[x].dfn
    
    struct edge{
    	int v, next;
    }e[MAXN<<1];
    struct node{
    	int fa, dep, siz, dfn;
    }nd[MAXN];
    int cntS, lim;
    int hd[MAXN], cntE, bit[MAXN];
    bool sel[MAXN]; int cntSel;
    
    void AddE(int u, int v);
    void DFS(int now, int fa);
    int Lowbit(int x);
    void Update(int pos, int val);
    int GetSum(int pos); 
    
    int main(){
    	int n, k;
    
    	scanf("%d%d", &n, &k);
    
    	k = n - k; // 删除点数转化为保留点数
    
    	lim = n;
    
    	for(int i = 1, u, v; i <= n-1; i++){
    		scanf("%d%d", &u, &v);
    		AddE(u, v); AddE(v, u);
    	}
    
    
    	DFS(n, 0);
    	sel[n] = 1;
    
    	for(int i = n; i >= 1; i--){
    		if((!sel[i]) && (dep(i)-GetSum(dfn(i))+cntSel  <= k)){ // 要求选择当前点后新增点数不超过总保留点数
    			for(int now = i; now != n; now = fa(now)){
    				if(sel[now]){
    					break;
    				}
    				else{
    					sel[now] = 1;
    					Update(dfn(now), 1); Update(dfn(now)+siz(now), -1); // 差分
    					cntSel++;
    				}
    			}
    		}
    	}
    
    	for(int i = 1; i <= n; i++){
    		if(!sel[i]){
    			printf("%d ", i);
    		}
    	}
    
    	return 0;
    }
    
    int GetSum(int pos){
    	int ans = 0;
    	while(pos){
    		ans += bit[pos];
    		pos -= Lowbit(pos);
    	}
    	return ans;
    }
    
    void Update(int pos, int val){
    	while(pos <= lim){
    		bit[pos] += val;
    		pos += Lowbit(pos);
    	}
    }
    
    int Lowbit(int x){
    	return x & (-x);
    }
    
    void DFS(int now, int fa){
    	fa(now) = fa, dep(now) = dep(fa) + 1, siz(now) = 1, dfn(now) = ++cntS;
    
    	for(int i = hd[now]; i; i = e[i].next){
    		if(e[i].v == fa){
    			continue;
    		}
    
    		DFS(e[i].v, now);
    		siz(now) += siz(e[i].v);
    	}
    }
    
    void AddE(int u, int v){
    	e[++cntE] = (edge){v, hd[u]};
    	hd[u] = cntE;
    }
    
  • 相关阅读:
    接口性能测试方案
    如何选择自动化测试框架
    一维和二维前缀和
    高精度 加减乘除
    归并排序 快速排序
    链表
    二分查找
    表达式求值
    c++ const问题小记
    虚继承总结
  • 原文地址:https://www.cnblogs.com/Foggy-Forest/p/13635018.html
Copyright © 2011-2022 走看看