题意

你有一颗 个节点的有根树(以 号节点为根),求最少加入多少条边之后使得根节点(即 号节点)到这棵树上任意一点的距离不大于

分析

考虑一种贪心,如果一个节点 到根的距离大于 的话,那么我们就从根节点连一条边到 节点的父亲

来考虑正确性的证明,一个节点 到根的距离如果大于了 ,那么只会有两种方式连边 直接连向 连向他的父亲节点

我们分两种情况讨论:

如果 的父亲节点 除了 以外还有别的子节点,那么连向父亲节点 也可以同时覆盖其他儿子。

如果 没有其他儿子,那么连向 可以使得根节点到 的距离也减小,虽然 可能满足距离小于等于 ,但这样一定不劣。

所以我们只需要每次找最远的点并连接根节点和它的父亲就好了。树上解决就好了。

代码

#include<bits/stdc++.h>
#define ll long long
const int N=2e5+5,INF=0x3f3f3f3f,mod=998244353;
using namespace std;

int n,cnt;
int head[N],f[N];
bool vis[N];
struct node
{
    int to,nxt;
}e[N<<1];
struct node1
{
    int num,dep;
}p[N<<1];

inline int read()
{
    register int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
    return x*f;
}

int qpow(int a,int b)
{
    int ans=1;
    while(b){if(b&1) ans=ans*a%mod;a=a*a%mod;b>>=1;}
    return ans;
}

bool cmp(node1 a,node1 b)
{
    return a.dep>b.dep;
}

void add(int u,int v)
{
    e[++cnt].nxt=head[u];
    e[cnt].to=v;
    head[u]=cnt;
}

void bfs(int rt)
{
    queue <int> q;
    p[rt].dep=0;p[rt].num=rt;
    q.push(rt);
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        for(int i=head[u];i;i=e[i].nxt)
        {
            int y=e[i].to;
            if(p[y].dep) continue;
            p[y].dep=p[u].dep+1;p[y].num=y;
            f[y]=u;
            q.push(y);
            if(p[y].dep<=2) vis[y]=1;
        }
    }
}

int main()
{
    n=read();
    for(int i=1;i<n;i++)
    {
        int u=read(),v=read();
        add(u,v);add(v,u);
    }
    bfs(1);
    sort(p+1,p+n+1,cmp);
    int ans=0;
    for(int i=1;i<=n;i++)
    {
        if(vis[p[i].num])    continue;
        ans++;
        int u=f[p[i].num];
        vis[u]=1;
        for(int j=head[u];j;j=e[j].nxt) vis[e[j].to]=1;
    }
    printf("%d\n",ans);
    return 0;
}
/*
7
1 2
2 3
2 4
4 5
4 6
5 7

7
1 2
1 3
2 4
2 5
3 6
1 7

7
1 2
2 3
3 4
3 5
3 6
3 7
*/