您的位置:首页 > 其它

bzoj 2525: [Poi2011]Dynamite

2018-03-14 09:49 369 查看

题意:

某个点上的引线被点燃后的1单位时间内,在树上和它相邻的点的引线会被点燃。如果一个有炸药的点的引信被点燃,那么这个点上的炸药会爆炸。

求引爆所有炸药的最短时间。

题解:

二分+贪心。

关键是想到二分,然后就好做了。

变成已知覆盖范围,问至少要多少个点覆盖所有染色点。

显然贪心是对的,不到临界点不点燃。

code:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,d[300010];
struct node{
int y,next;
}a[600010];int len=0,last[300010];
void ins(int x,int y)
{
a[++len].y=y;
a[len].next=last[x];last[x]=len;
}
int num;
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;
}
int f[300010],g[300010];
void dfs(int x,int fa,int t)
{
if(d[x]) f[x]=0;
for(int i=last[x];i;i=a[i].next)
{
int y=a[i].y;
if(y==fa) continue;
dfs(y,x,t);
if(f[y]!=-1) f[x]=max(f[x],f[y]+1);
if(g[y]!=-1) g[x]=max(
11874
g[x],g[y]-1);
}
if(f[x]<=g[x]) f[x]=-1;
if(f[x]==t) f[x]=-1,g[x]=t,num++;
if(x==1&&f[x]!=-1) num++;
}
bool check(int t)
{
num=0;
memset(f,-1,sizeof(f));
memset(g,-1,sizeof(g));
dfs(1,0,t);
return num<=m;
}
int main()
{
n=read();m=read();
for(int i=1;i<=n;i++) d[i]=read();
for(int i=1;i<n;i++)
{
int x,y;x=read();y=read();
ins(x,y);ins(y,x);
}
int l=0,r=n,ans;
while(l<=r)
{
int mid=(l+r)/2;
if(check(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
printf("%d",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: