Bzoj 2525 [Poi2011]Dynamite

2525: [Poi2011]Dynamite

Time Limit: 30 Sec  Memory Limit: 128 MB
Submit: 240  Solved: 120
[Submit][Status][Discuss]

Description

The Byteotian Cave is composed of  n chambers and n-1 corridors that connect them. For every pair of chambers there is unique way to move from one of them to another without leaving the cave. Dynamite charges are set up in certain chambers. A fuse is laid along every corridor. In every chamber the fuses from the adjacent corridors meet at one point, and are further connected to the dynamite charge if there is one in the chamber. It takes exactly one unit of time for the fuse between two neighbouring chambers to burn, and the dynamite charge explodes in the instant that fire reaches the chamber it is inside.
We would like to light the fuses in some m chambers (at the joints of fuses) in such a way that all the dynamite charges explode in the shortest time possible since the fuses are lit. Write a program that will determine the minimum such time possible.
 
Byteotian Cave的结构是一棵N个节点的树,其中某些点上面已经安置了炸 药,现在需要点燃M个点上的引线引爆所有的炸 药。
某个点上的引线被点燃后的1单位时间内,在树上和它相邻的点的引线会被点燃。如果一个有炸 药的点的引信被点燃,那么这个点上的炸 药会爆炸。
求引爆所有炸 药的最短时间。

输入:
第一行是两个整数N,M。(1<=m<=n<=300000)
接下来一行有N个整数Di,第I个数为1表示该点有炸 药。
接下来N-1行每行有两个数A,B,表示A和B之间有一条边。
输出:
最短时间。
样例解释: 
点燃3,5上的引线。

Input

The first line of the standard input holds two integers n and m (1<=M<=N<=300000)
, separated by a single space, that denote, respectively, the number of chambers in the cave and the number of chambers in which fire can be set to the fuses. The chambers are numbered from 1 to n . The next line contains  n integers d1,d2…dn (Di属于{0,1}, separated by single spaces. If Di=1 , then there is dynamite in the -th chamber, and if di=0 , there is none. The following n -1 lines specify the corridors of the cave. Each of them holds two integers a,b (a<=a<b<=n), separated by a single space, denoting that there is a corridor connecting the chambers a and b . Every corridor appears exactly once in the description.
You may assume that in tests worth 10% of the points it holds additionally that n<= 10, while in tests worth 40% of the points it holds that N<=1000.

Output

The first and only line of the standard output should hold a single integer, equal to the minimum time it takes from lighting the fuses to the explosion of all the charges.

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
  这道题还算比较水,上来以为所有点都放了炸 弹,那么果断二分答案+贪心啊。然而看到不是每个点都有炸弹后感觉这个人都不好了……
  然后果断重新想,发现二分答案还是可行的,仍然是尽可能的不到不点不行的时候点……
  然后又开始继续打码,好不容易打完了又发现自己打的还是错的,心痛……
  然而再接再厉,接着去分析。我们把所有节点分为3类。第一类,下面全是引线,没有炸弹。那么,我们可以直接忽略它。第二种,底下是炸弹,并且没有被点燃,这时,我们就要把它的子树中的离当前节点最远的状态传上来了。第三种,就是下面已经有引线被点燃,而且它有可能接着在我们规定的时间内点燃其他炸弹,与第二种相反,我们要找的是离当前节点最近的。
  在我们搜到一个点后,我们统计来自他子树的答案,如果下面都是引线,那么这个节点的状态就看他是不是炸弹了。如果他下面只有被点燃的引线,我们找到离他最近的引线转移过去,当然,如果他与引线的距离远,我们就没必要传递了。如果下面只有炸弹,我们就要看一下最远的炸弹离他是多远了。如果比当前值小,我们就直接传下去就行,否则将该点点燃,然后将状态改为点燃引线,接着传递。
  比较复杂的是下面既有被点燃的引线又有炸弹。我们需要分类讨论一下,如果引线可以点燃炸弹就把他的状态定为被点燃的引线,否则就改为炸弹,记得在这里也判断一下炸弹是否需要点燃,否则WA到死。最后判断一下根节点是什么状态,如果是炸弹我们还是要再点一个的。
  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstdio>
  4 #include <cstring>
  5 #include <algorithm>
  6 #include <cmath>
  7 #include <queue>
  8 #include <map>
  9 #include <set>
 10 #include <vector>
 11 #define N 300005
 12 using namespace std;
 13 int n,a[N],zz,m;
 14 struct no
 15 {
 16     int to,next;
 17 }road[N*2];
 18 void build(int x,int y)
 19 {
 20     zz++;
 21     road[zz].to=y;
 22     road[zz].next=a[x];
 23     a[x]=zz;
 24 }
 25 int bom[N];
 26 int size[N],fa[N];
 27 void dfs1(int x)
 28 {
 29     size[x]=1;
 30     for(int i=a[x];i>0;i=road[i].next)
 31     {
 32         int y=road[i].to;
 33         if(y==fa[x])continue;
 34         fa[y]=x;
 35         dfs1(y);
 36         size[x]+=size[y];
 37     }
 38 }
 39 int sum,f[N],c[N];
 40 void dfs(int x,int t)
 41 {
 42     if(size[x]==1)
 43     {
 44         if(bom[x])
 45         {
 46             c[x]=1;
 47             f[x]=0;
 48             if(t==0)
 49             {
 50                 sum++;
 51                 f[x]=0;
 52                 c[x]=2;
 53             }
 54         }
 55         else
 56         {
 57             c[x]=-1;
 58             f[x]=-1;
 59         }
 60         return;
 61     }
 62     int mn=0x7fffffff,mx=-2;
 63     bool yx=1;
 64     for(int i=a[x];i>0;i=road[i].next)
 65     {
 66         int y=road[i].to;
 67         if(y==fa[x])continue;
 68         dfs(y,t);
 69         if(c[y]==-1)continue;
 70         yx=0;
 71         if(c[y]==2)
 72         {
 73             if(f[y]+1<=t) mn=min(mn,f[y]+1);
 74         }
 75              
 76         else
 77             mx=max(mx,f[y]+1);
 78     }
 79     if(yx)
 80     {
 81         c[x]=-1;f[x]=-1;
 82         if(bom[x])
 83         {
 84             c[x]=1;
 85             f[x]=0;
 86             if(t==0)
 87             {
 88                 sum++;
 89                 c[x]=2;
 90             }
 91         }
 92         return;
 93     }
 94     if(mx==-2&&mn!=0x7fffffff)
 95     {
 96         c[x]=2;
 97         f[x]=mn;
 98         return;
 99     }
100     if(mx==-2&&mn==0x7fffffff)
101     {
102         if(bom[x])
103         {
104             c[x]=1;
105             f[x]=0;
106             if(t==0)
107             {
108                 sum++;
109                 f[x]=0;
110                 c[x]=2;
111             }
112         }
113         else
114         {
115             c[x]=-1;
116             f[x]=-1;
117         }
118         return;
119     }
120     if(mn==0x7fffffff)
121     {
122         if(mx>=t)
123         {
124             sum++;
125             f[x]=0;
126             c[x]=2;
127         }
128         else
129         {
130             c[x]=1;
131             f[x]=mx;
132         }
133         return;
134     }
135     if(mn+mx<=t)
136     {
137         c[x]=2;
138         f[x]=mn;
139         return;
140     }
141     if(mx>=t)
142     {
143         sum++;
144         f[x]=0;
145         c[x]=2;
146     }
147     else
148     {
149         c[x]=1;
150         f[x]=mx;
151     }
152 }
153 bool check(int k)
154 {
155     memset(c,0,sizeof(c));
156     memset(f,0,sizeof(f));
157     sum=0;
158     dfs(1,k);
159     if(c[1]==1)sum++;
160     return sum<=m;
161 }
162 int main()
163 {
164     scanf("%d%d",&n,&m);
165     for(int i=1;i<=n;i++)
166     {
167         scanf("%d",&bom[i]);
168     }
169     for(int i=1;i<n;i++)
170     {
171         int x,y;
172         scanf("%d%d",&x,&y);
173         build(x,y);
174         build(y,x);
175     }
176     dfs1(1);
177     int li=0,ri=n,mid;
178     while(li<=ri)
179     {
180         mid=(li+ri)>>1;
181         if(check(mid)) ri=mid-1;
182         else li=mid+1;
183     }
184     printf("%d
",ri+1);
185     return 0;
186 }
View Code
原文地址:https://www.cnblogs.com/liutianrui/p/7759750.html