其他分享
首页 > 其他分享> > 【洛谷P3523】DYN-Dynamite

【洛谷P3523】DYN-Dynamite

作者:互联网

前言

开学了,几天没写题了。今天政治课出来随机跳了一道题写写。。。

题目

题目链接:https://www.luogu.com.cn/problem/P3523
给一棵树,树上有一些关键节点,要求你选\(m\)个点,使得关键节点到这些点中距离的最小值的最大值最小,求这个值。

思路

\(\operatorname{Update:}\) 标记点即关键点。
最大值最小,套路性二分转变为判定性问题。
假设现在二分到最大距离为\(mid\),我们只需要判断若使每一个关键节点到选择的点的距离不超过\(mid\),最小选取点的个数是否不超过\(m\)即可。
容易想到,如果在\(x\)的子树下我们已经选择了若干个点,设\(x\)子树内没有被覆盖的标记点到\(x\)的距离为\(dis\),如果\(dis<mid\),那么显然没有必要选择\(x\)点,因为在\(x\)的父亲上选显然更优。
所以我们得到了一个结论:选取一个点,当且仅当在它的子树内没有被覆盖的标记点到该点的距离等于\(mid\)。
那么这样就可以贪心选点了。设\(f[x][1]\)表示\(x\)的子树内最远没有被覆盖的标记点到\(x\)的距离,\(f[x][2]\)表示\(x\)的子树内最近的被选择的点到\(x\)的距离。
显然有
\[f[x][1]=\max_{v\in x's\ son}(f[v][1]+1)\]
\[f[x][2]=\min_{v\in x's\ son}(f[v][2]+1)\]
那么在\(x\)的各个儿子的子树互相做贡献,如果\(f[x][1]+f[x][2]\leq mid\),那么\(x\)的其中一棵子树的选择的点可以将其他所有子树的未覆盖标记点,那么就将\(f[x][1]\)赋值为\(-\infty\)。
如果\(f[x][1]=mid\),那么必须选择\(x\)点,此时\(f[x][1]=-\infty,f[x][2]=0\)。并且选择的节点数加一。
最后记得特判根节点。
时间复杂度\(O(n\log n)\)

代码

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int N=300010,Inf=1e9;
int n,m,tot,l,r,mid,cnt,head[N],f[N][3];
bool flag[N];

struct edge
{
    int next,to;
}e[N*2];

void add(int from,int to)
{
    e[++tot].to=to;
    e[tot].next=head[from];
    head[from]=tot;
}

void dfs(int x,int fa)
{
    f[x][1]=-Inf; f[x][2]=Inf;
    if (flag[x]) f[x][1]=0;
    for (int i=head[x];~i;i=e[i].next)
    {
        int v=e[i].to;
        if (v!=fa)
        {
            dfs(v,x);
            f[x][1]=max(f[x][1],f[v][1]+1);
            f[x][2]=min(f[x][2],f[v][2]+1);
        }
    }
    if (f[x][1]+f[x][2]<=mid) f[x][1]=-Inf;
    if (f[x][1]>=mid) cnt++,f[x][2]=0,f[x][1]=-Inf;
}

int main()
{
    memset(head,-1,sizeof(head));
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
        scanf("%d",&flag[i]);
    for (int i=1,x,y;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        add(x,y); add(y,x);
    }
    l=0; r=n;
    while (l<=r)
    {
        mid=(l+r)>>1; cnt=0;
        dfs(1,0);
        if (f[1][1]>=0) cnt++;
        if (cnt<=m) r=mid-1;
            else l=mid+1;
    }
    printf("%d\n",r+1);
    return 0;
}

标签:head,洛谷,子树内,int,mid,tot,DYN,cnt,P3523
来源: https://www.cnblogs.com/stoorz/p/12331969.html