当前位置: 代码迷 >> 综合 >> P3523 [POI2011]DYN-Dynamite
  详细解决方案

P3523 [POI2011]DYN-Dynamite

热度:1   发布时间:2023-12-15 08:31:54.0

前言

这道题是一个树上二分的题,其实很有思维量的

思路

首先这是一道让选择m个节点,每一个点到关键节点的距离的最小值中的最大值最小化的一道题目

首先第一个最小值就是每一个选定节点到最近的关键节点的距离,其实不用太在意,之后就是最大值最小化,这显然是二分答案的一道题,所以考虑二分一个mid,看看可不可以用mid的距离去覆盖全部的关键节点,之后就是考虑这个check

check

首先我们可以用覆盖的思想去理解这道题,就是每一个选定节点可以覆盖全部的关键节点就是一个true,那么我们就用两个数组
f[x] --> 表示以x为root的子树中距离最大的没有覆盖的关键节点的dis
g[x] – > 表示以x为root的子树中距离最近的选定节点的距离

那么转移就是 f[x]=max(f[x],f[y]+1) g[x]=min(g[x],g[y]+1)

这个比较显然,注意最开始f[x]=-inf g[x]=inf

那么之后就是考虑对于节点的选定

假如 1.f[x]+g[x]<=mid 也就说明这个子树的全部关键节点都可以被覆盖
2. g[x]>mid && b[x] == 1 也就是说明这个点是关键节点,并且没人可以管,所以就交给父亲处理 所以f[x]=max(f[x],0)
3. f[x] = mid 也就是说明这个子树内有一个关键节点没有办法被任何人覆盖,只有这个点,所以tot++

最后就是二分了

注意

二分的左边界可以为0,因为我可以距离为0

还有就是dfs结束后我们要特判一下根的f,假如有节点没有被覆盖,那么就要tot++,也就是把根给加上

code

#include<bits/stdc++.h>
using namespace std;
#define max(a,b) ((a)>(b)? a : b)
#define min(a,b) ((a)>(b)? b : a)
#define ll long long
const int maxn=300005;
const ll inf=1e9;
int n,m