zoukankan      html  css  js  c++  java
  • 【BZOJ2525】[Poi2011]Dynamite 二分+树形DP

    【BZOJ2525】[Poi2011]Dynamite

    Description

    Byteotian Cave的结构是一棵N个节点的树,其中某些点上面已经安置了炸.药,现在需要点燃M个点上的引线引爆所有的炸.药。
    某个点上的引线被点燃后的1单位时间内,在树上和它相邻的点的引线会被点燃。如果一个有炸.药的点的引信被点燃,那么这个点上的炸.药会爆炸。
    求引爆所有炸.药的最短时间。
    输入:
    第一行是两个整数N,M。(1<=m<=n<=300000)
    接下来一行有N个整数Di,第I个数为1表示该点有炸.药。
    接下来N-1行每行有两个数A,B,表示A和B之间有一条边。
    输出:
    最短时间。
    样例解释: 
    点燃3,5上的引线。

    Sample Input

    7 2
    1 0 1 1 0 1 1
    1 3
    2 3
    3 4
    4 5
    5 6
    5 7

    Sample Output

    1

    题解:一眼想到二分+贪心,但是细节还是极其多的~

    首先二分时间limit,然后用f[i]表示i子树中,最少要点燃多少引线。但是i子树中的部分炸.药可能由i子树外的点引燃,所以设g[i]表示在f[i]最小的前提下,最少有多少层还没有被点燃;i子树中的引线也可能引燃子树外的炸.药,所以h[i]表示在f[i]最小的前提下,最多还能点燃子树外的多少层炸.药。显然g[x]和h[x]同时只能存在一个。

    转移时细节挺多的,见代码吧~

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int maxn=300010;
    int n,m,cnt,mid;
    int to[maxn<<1],next[maxn<<1],head[maxn],d[maxn],f[maxn],g[maxn],h[maxn];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    inline void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    void dfs(int x,int fa)
    {
    	int i,y;
    	if(d[x])	g[x]=0,h[x]=-1<<20;
    	else	g[x]=h[x]=-1<<20;
    	f[x]=0;
    	for(i=head[x];i!=-1;i=next[i])	if(to[i]!=fa)
    	{
    		y=to[i],dfs(y,x),f[x]+=f[y],g[x]=max(g[x],g[y]+1),h[x]=max(h[x],h[y]-1);
    	}
    	if(h[x]>=g[x])	g[x]=-1<<20;
    	else	if(g[x]<mid)	h[x]=-1<<20;
    	else	f[x]++,g[x]=-1<<20,h[x]=mid;
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,a,b,l=0,r=n;
    	memset(head,-1,sizeof(head));
    	for(i=1;i<=n;i++)	d[i]=rd();
    	for(i=1;i<n;i++)	a=rd(),b=rd(),add(a,b),add(b,a);
    	while(l<r)
    	{
    		mid=(l+r)>>1,dfs(1,0);
    		if(g[1]>=0)	f[1]++;
    		if(f[1]<=m)	r=mid;
    		else	l=mid+1;
    	}
    	printf("%d",r);
    	return 0;
    }//5 0 0 0 0 0 0 1 2 2 3 3 4 4 5

     

  • 相关阅读:
    ContentControl 嵌套后 Foreground 无法继承
    Windows Phone 开发学习
    Windows 8 Metro 风格应用开发
    微信小程序中时间戳和日期的相互转换
    二维数组,要求按考试分数高到低排序,如果考试分数相同就按违纪扣分低到高排序
    微信小程序实现按首字母检索城市列表
    微信40125错误
    sublime text3 英文版转为中文版
    html5代码如何转成小程序代码
    阿里云刘强:无影云电脑构建云上安全办公室
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7859067.html
Copyright © 2011-2022 走看看