[bzoj 2525--Poi2011]Dynamite
作者:互联网
Byteotian Cave的结构是一棵N个节点的树,其中某些点上面已经安置了炸药,现在需要点燃M个点上的引线引爆所有的炸药。
某个点上的引线被点燃后的1单位时间内,在树上和它相邻的点的引线会被点燃。如果一个有炸药的点的引信被点燃,那么这个点上的炸药会爆炸。
求引爆所有炸药的最短时间。
好题啊。这种题竟然是“边权相等就贪心,边权不等就dp”。。。
首先二分答案,然后问题就转化成一个点如果点燃它的引线就能覆盖与它距离<=mid的点,求用最少的点来覆盖所有炸药点。关键是边权都为1,所以可以贪心。
f[x]表示在x的子树内未被覆盖的与x距离最远的炸药点距离,g[x]表示在x的子树内与x距离最近的点燃点距离。
如果f[x]+g[x]<=mid,那么就说明x子树内就可以搞定。
如果f[x]==mid,那么就说明x一定要被点燃。
剩下的情况就可以留给祖先处理。
那最后注意一下细节就可以了。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
using namespace std;
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*10+ch-'0',ch=getchar();
return x*f;
}
inline void write(int x)
{
if(x<0)putchar('-'),x=-x;
if(x>9)write(x/10);
putchar(x%10+'0');
}
inline void pr1(int x){write(x),putchar(' ');}
inline void pr2(int x){write(x),puts("");}
struct node
{
int x,y,next;
}a[600010];int len,last[300010];
bool v[300010];
inline void ins(int x,int y)
{
len++;
a[len].x=x;a[len].y=y;
a[len].next=last[x];last[x]=len;
}
int n,limit,w;
int f[300010],g[300010];
inline void solve(int x,int fa)
{
g[x]=n,f[x]=0;
for(int k=last[x];k;k=a[k].next)
{
int y=a[k].y;
if(y==fa)continue;
solve(y,x);
f[x]=max(f[x],f[y]+1);g[x]=min(g[x],g[y]+1);
}if(v[x]==false && !f[x])f[x]=-1;
if(f[x]+g[x]<=limit)f[x]=-1;
else if(f[x]==limit || (x==1 && f[x]>=0)){w++;f[x]=-1,g[x]=0;}
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
n=read();int m=read();
for(int i=1;i<=n;i++)v[i]=read();
for(int i=1;i<n;i++){int x=read(),y=read();ins(x,y),ins(y,x);}
int l=0,r=n,ans;
while(l<=r)
{
int mid=(l+r)>>1;limit=mid,w=0;solve(1,0);
if(w<=m)ans=mid,r=mid-1;
else l=mid+1;
}pr2(ans);
return 0;
}
标签:2525,ch,int,点燃,Poi2011,len,inline,Dynamite,include 来源: https://blog.csdn.net/lixuanjing2016/article/details/89789625