P3523 POI2011 DYN-Dynamite

P3523 POI2011 DYN-Dynamite

小 trick,加双倍经验。

思路

使 dis 的最大值最小,可以想到二分 dis,然后根据 dis 判断可行性。

那么可以把问题转化为,所有关键点到选择的点的距离小于 dis 的前提下,使得使用的点的个数最小。

这就是:P3942 将军令

考虑设 f[u] 为距离 u 最近的选中的点的距离,g[u] 为距离 u 最远的未被覆盖的关键点的距离。

这里覆盖指:对于一个关键点,到最近的被选中点的距离小于等于当前二分的 dis

有朴素转移:

f[u]=max(f[u],f[v]+1)

g[u]=max(g[u],g[v]+1)

然后要分讨一下(下文中的 mid 为二分的距离):

  1. f[u]>midu 为关键点。

    g[u]=max(g[u],0)

    解释:显而易见,当前点可以作为一个没有被覆盖的关键点。

  2. g[u]+f[u]mid。​

    g[u]=

    解释:显然没有一个没被覆盖的关键点,易证 g[u]f[u] 不来自一棵子树。

  3. g[u]=mid

    g[u]=,f[u]=0​ 且需选择的点个数加一。

    解释:该点必须被选择。

最后判断一下根的 g[u] 是否大于 0,如果大于 0 在加一个选中的点。

然后套上二分就 OK 了。

CODE

#include<bits/stdc++.h>
using namespace std;

const int maxn=3e5+5;

struct Edge
{
    int tot;
    int head[maxn];
    struct edgenode{int to,nxt;}edge[maxn*2];
    inline void add(int x,int y)
    {
        tot++;
        edge[tot].to=y;
        edge[tot].nxt=head[x];
        head[x]=tot;
    }
}T;

int n,m;
int a[maxn];

int g[maxn],f[maxn];

int gs;
inline void dfs(int u,int fa,int mid)
{
    g[u]=-1e9,f[u]=1e9;
    for(int i=T.head[u];i;i=T.edge[i].nxt)
    {
        int v=T.edge[i].to;
        if(v==fa) continue;
        dfs(v,u,mid);
        f[u]=min(f[v]+1,f[u]);
        g[u]=max(g[v]+1,g[u]);
    }
    if(f[u]>mid&&a[u]) g[u]=max(g[u],0);
    if(f[u]+g[u]<=mid) g[u]=-1e9;
    if(g[u]==mid) f[u]=0,g[u]=-1e9,gs++;
}
inline void solve(int mid)
{
    gs=0;
    dfs(1,0,mid);
    gs+=(g[1]>=0);
    printf("%d",gs);
}

int main()
{
    int t;
    scanf("%d%d%d",&n,&m,&t);
    for(int i=1;i<=n;i++) a[i]=1;
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        T.add(u,v),T.add(v,u);
    }
    solve(m);
}
posted @   彬彬冰激凌  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示