• P3523 [POI2011]DYN-Dynamite


    题目描述

    给一棵树,树上有一些关键节点,要求你选(m)个点,使得关键节点到这些点中距离的最大值最小,求这个值。

    题解

    最大值最小,考虑二分答案,二分这个最小值。

    那么怎么判断呢,我们只需要记录一下至少要选多少个点,只要点数(leq m)则合法。

    考虑树形(dp),设(f1[x])表示(x)的子树中距离它最远的关键点到它的距离,设(f2[x])表示(x)的子树中距离它最近的选出的点到它的距离,(is[x])表示(x)这个节点是否为关键节点。

    首先从儿子向父亲转移时显然(f1[x] = max(f1[x], f1[y] + 1), f2[x] = min(f2[x], f2[y] + 1)),其中(y)(x)的儿子,初始化(f1[x] = - inf, f2[x] = inf)

    (is[x]),则(f1[x] = max(0, f1[x]))
    (f1[x] + f2[x] <= mid),则(f1[x] = -inf)
    (f1[x] == mid),则(f1[x] = - inf, f2[x] = 0, cnt ++)。(表示这个点被选了)。

    注:最后判断一下根节点是否还需要选上。

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int N = 3e5 + 5;
    const int inf = 0x3f3f3f3f;
    int n, m, is[N], ans, head[N], tot, cnt, f1[N], f2[N];
    struct node{int to, nex;}a[N << 1];
    inline int read()
    {
    	int x = 0, f = 1; char ch = getchar();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
    	while(ch >= '0' && ch <= '9') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();}
    	return x * f;
    }
    void add(int x, int y) {a[++ tot].to = y; a[tot].nex = head[x]; head[x] = tot;}
    void dfs(int x, int fa, int mid)
    {
    	f1[x] = - inf; f2[x] = inf;
    	for(int i = head[x]; i; i = a[i].nex)
    	{
    		int y = a[i].to;
    		if(y == fa) continue;
    		dfs(y, x, mid);
    		f1[x] = max(f1[x], f1[y] + 1);
    		f2[x] = min(f2[x], f2[y] + 1);
    	}
    	if(is[x]) f1[x] = max(0, f1[x]);
    	if(f1[x] + f2[x] <= mid) f1[x] = - inf;
    	if(f1[x] == mid) f1[x] = - inf, f2[x] = 0, cnt ++;
    }
    int check(int mid)
    {
    	cnt = 0; dfs(1, 0, mid);
    	if(f1[1] >= 0) cnt ++;
    	return cnt <= m;
    }
    void work()
    {
    	n = read(); m = read();
    	for(int i = 1; i <= n; i ++) is[i] = read();
    	for(int i = 1, x, y; i < n; i ++) {x = read(); y = read(); add(x, y); add(y, x);}
    	int l = 0, r = n;
    	while(l <= r)
    	{
    		int mid = (l + r) >> 1;
    		if(check(mid)) ans = mid, r = mid - 1;
    		else l = mid + 1;
    	}
    	printf("%d
    ", ans);
    }
    int main() {return work(), 0;}
    
  • 相关阅读:
    Vue v-if v-for v-bind v-on
    Vue v-bind的使用
    Vue绑定事件
    vue绑定内联样式
    Vue简单使用
    js实现UTC时间转为北京时间,时间戳转为时间
    setTimeOut函数传参数
    直播聊天室,点亮效果,jquery实现
    聊天室自动滚动效果实现
    融云rongCloud聊天室的使用
  • 原文地址:https://www.cnblogs.com/Sunny-r/p/12651879.html
Copyright © 2020-2023  润新知