bzoj2525: [Poi2011]Dynamite

题目
思路出处
感觉这题就是消防局的设立+ n 开大 300 倍+距离为任意数+二分答案
显然,这题就是二分答案后,把当前最深的点向上 n o w 单位,然后覆盖这个点,并把 n o w 距离内的全覆盖一遍,但这样很难写,要稍微换一下写法
f [ u ] [ 0 ] 表示以 u 为根的子树中目前还没有人管理的关键点距离 u 的最远的距离
f [ u ] [ 1 ] 表示以 u 为根的子树中选择了的点距离 u 的最近的距离
详见代码注释

#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);
}

猜你喜欢

转载自blog.csdn.net/xumingyang0/article/details/81047871
今日推荐