首页 > 其他分享 >CF1385F Removing Leaves 题解

CF1385F Removing Leaves 题解

时间:2024-02-07 10:14:12浏览次数:28  
标签:int 题解 Leaves son 叶子 edge Removing include 节点

解题思路

简单贪心,优先选择叶子节点最多的,这样能够保证一定能把所有能删的都删了。

因为要建一个可删除的图,所以我们可以使用 set 来存边,不然就需要维护一堆东西……那么我们肯定是从有叶子节点的点向父亲更新的,那么我们每次选择叶子节点最多的点,然后删除 \(k\) 个叶子,判断一下删除后该节点是否为叶子节点,如果是,那么更新父亲节点的叶子节点数量,否则把这个节点从新插入 set 中。

AC 代码

#include<stdio.h>
#include<stdlib.h>
#include<set>
#include <vector>
#define N 200005
int n,k,in[N],son[N];
std::set<int> edge[N];
struct cmp{
    inline bool operator()(
        const int a,
        const int b
    ) const {
        if(son[a]!=son[b])
            return son[a]>son[b];
        return a<b;
    }
};
inline void work(){
    scanf("%d%d",&n,&k);int u,v;
    for(register int i=1;i<=n;++i)
        edge[i].clear(),son[i]=in[i]=0;
    for(register int i=1;i<n;++i){
        scanf("%d%d",&u,&v);
        edge[u].insert(v);
        edge[v].insert(u);
        ++in[u],++in[v];
    }std::set<int,cmp> s;
    for(register int i=1;i<=n;++i){
        if(in[i]>1) continue;
        auto v=*edge[i].begin();
        edge[i].erase(v);
        edge[v].erase(i);
        ++son[v];
    }int ans=0;
    for(register int i=1;i<=n;++i)
        s.insert(i);
    while(!s.empty()){
        auto now=*s.begin();
        if(son[now]<k) break;
        ++ans;s.erase(now);
        son[now]-=k;
        if(!son[now]&&edge[now].size()==1){
            if(edge[now].empty())
                continue;
            auto v=*edge[now].begin();
            edge[now].erase(v);
            edge[v].erase(now);
            s.erase(v);++son[v];
            s.insert(v);
        }else s.insert(now);
    }printf("%d\n",ans);
}
signed main(){
    int T;scanf("%d",&T);
    while(T--) work();
}

标签:int,题解,Leaves,son,叶子,edge,Removing,include,节点
From: https://www.cnblogs.com/UncleSamDied6/p/18010663

相关文章

  • CF1415E New Game Plus! 题解
    解题思路简单贪心题,我们可以把整个序列看作\(k+1\)个可重集,首先可以得到一个显然的结论:较大的数一定比较小的数先放入一个集合中。同样,由于每一轮\(ans\getsans+\maxsum_i\),其中\(sum_i\)表示第\(i\)个集合的元素和,那么,我们一定会将当前的元素放入当前和最大的哪个集合......
  • CF1416B Make Them Equal 题解
    解题思路观察可以发现,每次操作后序列元素之和不变,那么我们可以将每一次操作看作是\(a_i\)向\(a_j\)移动了\(i\timesx\)。由此可得,若序列和\(sum\bmodn\not=0\),那么一定无解,否则一定存在一个合法的操作方案。因为每次移动时移动的数应为\(i\)的倍数,所以\(a_1\)可以向......
  • CF1446C Xor Tree 题解
    解题思路与其考虑删除哪些点,不如考虑保留哪些点。考虑到和异或有关,那么我们可以把这些数倒序插入trie树中,然后我们就可以在trie树上跑一个简单的dp:若当前节点为叶子节点,那么保留,返回\(1\);若当前节点在链上,那么直接继承儿子节点;若当前节点有两个儿子,那么更新为较大儿子......
  • CF1922E Increasing Subsequences 题解
    解题思路因为可以有空集,那么我们首先构造第一段最长的连续上升的序列,那么这段序列中共有\(2^{\mids\mid}\)个上升子序列。接下来我们考虑补全剩余的,我们不妨将剩余的部分全部设为连续不增序列,那么设当前位置在第一段中有\(k\)个小于它的,那么添加这个数后可以增加\(2^{k-1}......
  • CF1413C Perform Easily 题解
    解题思路其实是很简单的一道题,考虑计算出所有\(b_i\)在减去每一个\(a_j\)后所有可能的值,将这个值按照从小到大的顺序排序,那么我们可以考虑固定最小值,查找最大值,这个时候从最小值到最大值的区间内应该每一种\(b_i\)都出现了一次。那么,我们可以使用一个桶或者map搭配双指针......
  • 洛谷P10135 暨 USACOJan2024S T2 题解
    题意简述给点一棵有\(n\)个节点的树,在每个时间点都会在某个节点出现一瓶药水,记\(p_i\)为第\(i\)个时间点出现药水的节点,定义一次遍历为从\(1\)号节点走到任意节点,要求在遍历次数最少的情况下拾取最多数量的药水。思维路径首先我们要探讨遍历次数最少的状态是怎样的。由......
  • CF1922B Forming Triangles 题解
    解题思路显然,有以下两种选择的方法:所有边一样长;两条一样长的边,第三条边小于这两条边。然后组合数计算即可。AC代码#include<stdio.h>#include<stdlib.h>#include<algorithm>#include<vector>#definelllonglong#defineN300005intn,a[N];inlinellC3(llx){......
  • CF1922C Closest Cities 题解
    解题思路贪心,能走距离最短的城市就一定走。分别考虑\(x>y\)和\(x<y\)的情况,两种情况分别是从后向前转移和从前往后转移,分别预处理一个前缀和和后缀和即可。AC代码#include<stdio.h>#include<stdlib.h>#include<valarray>#defineN100005#definelllonglongintn......
  • CF1338B Edge Weight Assignment 题解
    解题思路一种不需要树形dp的做法。因为是一颗无根树,所以我们不妨以重心为根。首先考虑边权最少的情况。可以发现这个时候对于任意两个叶子节点,我们可以分别考虑其到根节点的路径,这样对于求其路径的异或值是没有影响的,但是在这种情况下我们可以很方便的讨论其路径的奇偶性。令......
  • ABC335 A~E 题解
    A题目大意输入一个字符串,把这个字符串的最后一位改成4后输出这个字符串。解题思路直接模拟即可AC代码#include<iostream>#include<math.h>#include<time.h>#include<stdio.h>#include<algorithm>#definelllonglonginlinevoidwork(){std::strings;s......