bzoj 2525 [Poi2011]Dynamite
题解:
二分答案+贪心
这个树上贪心在回溯时处理,需要注意一些细节。
如果传上来的这棵子树有未炸的药,传最远药的距离。如果没有,传最近的点燃引线的距离。
在判断时,如果没有药,接着向上传引线。
如果有,但是最近的引线可以拐个弯在规定时间内炸掉最远的药,视为没有药。
否则,如果最远距离未超过规定时间,接着向上传药距离。
否则点燃这一点,向上传没有药。
注意<=与<以及0的特判。
代码:
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstring> 4 #include<cstdio> 5 #include<algorithm> 6 #include<cmath> 7 #include<queue> 8 using namespace std; 9 struct pai{ 10 int first,second; 11 }; 12 #define mmin(a,b) (a<b?a:b) 13 struct tree{ 14 int u,v,next; 15 }l[601000]; 16 int lian[301000],n,e,ans,m,num,jie,inf=100000000; 17 bool pd[301000]; 18 void bian(int,int); 19 pai dfs(int,int); 20 int main() 21 { 22 // freopen("in.txt","r",stdin); 23 scanf("%d%d",&n,&m); 24 for(int i=1;i<=n;i++) 25 { 26 int x; 27 scanf("%d",&x); 28 pd[i]=x; 29 } 30 for(int i=1;i<n;i++) 31 { 32 int x,y; 33 scanf("%d%d",&x,&y); 34 bian(x,y); 35 bian(y,x); 36 } 37 int le=0,ri=n; 38 while(le<=ri) 39 { 40 int mid=(le+ri)>>1; 41 num=0;jie=mid; 42 pai pa=dfs(1,1); 43 if(pa.second!=0) num++; 44 if(num<=m) 45 { 46 ans=mid; 47 ri=mid-1; 48 } 49 else 50 le=mid+1; 51 } 52 printf("%d\n",ans); 53 return 0; 54 } 55 void bian(int x,int y) 56 { 57 e++; 58 l[e].u=x; 59 l[e].v=y; 60 l[e].next=lian[x]; 61 lian[x]=e; 62 } 63 pai dfs(int x,int fa) 64 { 65 pai pa; 66 int yuan=inf,v; 67 int que[4]={0,0},size=0; 68 for(int i=lian[x];i;i=l[i].next) 69 { 70 v=l[i].v; 71 if(v!=fa) 72 { 73 pa=dfs(v,x); 74 if(pa.second==0) yuan=mmin(yuan,pa.first); 75 else 76 { 77 size++; 78 if(que[1]<pa.first) que[1]=pa.first; 79 if(que[0]<=pa.first) swap(que[0],que[1]); 80 } 81 } 82 } 83 if(pd[x]==1&&jie==0) 84 { 85 num++; 86 return (pai){0,0}; 87 } 88 if(size==0) 89 { 90 if(pd[x]==0||yuan<=jie) return (pai){yuan+1,0}; 91 return (pai){1,1}; 92 } 93 if(que[0]+yuan<=jie) 94 { 95 return (pai){yuan+1,0}; 96 } 97 if(que[0]<jie) return (pai){que[0]+1,1}; 98 num++; 99 return (pai){1,0}; 100 }