Luogu P3523 [POI2011]DYN-Dynamite

Descripe

如此多的最大最小,显然二分答案mid,则对于每一个关键点到所选的最近的点的距离<=mid

貌似是树形DP

令f[i]表示以i为根的子树中i到最远关键点(无人认领)的距离,

   g[i]表示                         i到最近选出点的距离

f[u]=max(f[v]+1),g[u]=min(g[v]+1);

如果f[u]=mid,那么无论如何,u都要被选,f[u]=-oo,g[u]=0,sum++;

如果u是关键点,那么f[u]=max(0,f[u]);

如果f[u]+g[u]<=mid,即可以在子树内部自己消化,故f[u]=-oo

最后注意f[1]>=0的时候要把1设为关键点。

 

注意特判超脱于五行之上的0(^.^)

#include<bits/stdc++.h>
const int INF=1e9;
using namespace std;

const int N=6e5+5;
int cnt,to[N],nxt[N],he[N],f[N],g[N],sum,n,m;
bool a[N];

inline void add(int u,int v) {
    to[++cnt]=v,nxt[cnt]=he[u],he[u]=cnt;
}

void dfs(int fa,int u,int k) {
    g[u]=INF,f[u]=-INF;
    for(int e=he[u];e;e=nxt[e]) {
        int v=to[e];
        if(v!=fa){
            dfs(u,v,k);
            f[u]=max(f[v]+1,f[u]);
            g[u]=min(g[v]+1,g[u]);
        }
    }
    if(f[u]==k) f[u]=-INF,g[u]=0,sum++;
    if(a[u]) f[u]=max(f[u],0);
    if(f[u]+g[u]<=k) f[u]=-INF;
}
int main() {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) {
        scanf("%d",&a[i]);
        if(a[i]) sum++;
    }
    if(sum==m) {
        puts("0"); return 0;
    }
    for(int i=1;i<n;i++) {
        int u,v; scanf("%d%d",&u,&v);
        add(u,v),add(v,u);
    }
    int l=1,r=n,ans;
    while(l<=r) {
        int mid=l+r>>1;
        sum=0;
        dfs(0,1,mid);
        if(f[1]>=0) sum++;
        if(sum<=m) {
            r=mid-1; ans=mid;
        } else l=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}

 

posted @ 2020-09-02 20:57  wwwsfff  阅读(192)  评论(0编辑  收藏  举报