题目
思路出处
感觉这题就是消防局的设立+ 开大 倍+距离为任意数+二分答案
显然,这题就是二分答案后,把当前最深的点向上 单位,然后覆盖这个点,并把 距离内的全覆盖一遍,但这样很难写,要稍微换一下写法
设 表示以 为根的子树中目前还没有人管理的关键点距离 的最远的距离
表示以 为根的子树中选择了的点距离 的最近的距离
详见代码注释
#include<bits/stdc++.h>
using namespace std;
const int N=300002;
struct node{
int to,ne;
}e[N<<1];
int n,m,i,x,y,l,r,mid,h[N],d[N],b[N],tot,ans,f[N][2],now;
inline char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline int read(){
int x=0,fl=1;char ch=gc();
for (;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
return x*fl;
}
void add(int x,int y){
e[++tot]=(node){y,h[x]};
h[x]=tot;
}
void dfs(int u,int fa){
int t1=d[u]?0:-1e9,t2=1e9;
for (int i=h[u],v;i;i=e[i].ne)
if ((v=e[i].to)!=fa){
dfs(v,u);
t1=max(t1,f[v][0]+1);//t1表示f[u][0]
t2=min(t2,f[v][1]+1);//t2表示f[u][1]
}
if (t1+t2<=now) t1=-1e9;
//假设u子树未被管理的最远关键点为v1,已经选了的最近点为v2,
//t1+t2<=now说明v1->u->v2的路径长<=now所以v2可以管理到v1,
//所以u子树中还没有无人管理的关键点,t1赋为-1e9,ps:这句话理解了半小时才懂QAQ
if (t1==now) tot++,t1=-1e9,t2=0;//因为再向上一个点,距离就超过now了,所以必须要选择u这个点
f[u][0]=t1;f[u][1]=t2;
}
bool check(int lim){
now=lim;tot=0;
dfs(1,0);
if (f[1][0]+f[1][1]>now) tot++;//特判根
return tot<=m;
}
int main(){
n=read();m=read();
for (i=1;i<=n;i++) d[i]=read();
for (i=1;i<n;i++){
x=read();y=read();
add(x,y);add(y,x);
}
l=0;r=n;
while (l<=r){
mid=l+r>>1;
if (check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d",ans);
}