據說這道題有ON做法
好像是真的
但是沒人寫
我也不會
所以我就寫了正常的做法啦
顯然要二分一下對吧
然後我們怎麼判斷呢?
考慮樹形DP:
表示以爲根節點的子樹中,最遠的沒有被覆蓋到的關鍵節點的距離
表示以爲根節點的自述中,最近的一個選擇的點的距離
那麼轉移顯然就是
但是還有別的情況啊,要不然答案就是0了啊
情況1
當時,讓子樹中所有未匹配的節點連向那個點就可以,清零
情況2
當時,需要選擇當前的點,清零,
情況3
當我們做到1的時候,如果還有沒覆蓋的,就要把1選上
那麼爲了便於處理,當清零的時候,我們讓,當清零的時候(當下面還沒有選過的時候),我們讓
然後還有一些細節,比如說二分的判斷之類的
我不會告訴你我在這上面調了一個小時因爲我對拍的暴力寫掛了
#include <bits/stdc++.h>
using namespace std;
# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)
typedef long long ll;
const int N=3e5+5;
template<typename T> void read(T &x){
x=0;int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
x*=f;
}
int n,m,ans,tot;
int head[N],cnt;
int f[N],g[N];
int col[N];
struct Edge{
int to,next;
}e[N<<1];
void add(int x,int y){
e[++cnt]=(Edge){y,head[x]},head[x]=cnt;
}
void dfs(int u,int fa,int delta){
if(!col[u])f[u]=-1;
else f[u]=0;
g[u]=2e9;
RepG(i,u){
int v=e[i].to;
if(v==fa)continue;
dfs(v,u,delta);
if(f[v]!=-1)f[u]=max(f[u],f[v]+1);
if(g[v]!=2e9)g[u]=min(g[u],g[v]+1);
}
if(f[u]!=-1){
if(g[u]==2e9){
if(f[u]==delta){
f[u]=-1;
tot++;
g[u]=0;
}
}
else{
if(g[u]+f[u]<=delta)f[u]=-1;
else if(f[u]==delta){
f[u]=-1;
tot++;
g[u]=0;
}
}
}
}
bool check(int delta){
tot=0;
dfs(1,0,delta);
if(f[1]!=-1)tot++;
return tot<=m;
}
int main()
{
memset(head,-1,sizeof(head));
read(n),read(m);
Rep(i,1,n)read(col[i]);
Rep(i,1,n-1){
int x,y;
read(x),read(y);
add(x,y),add(y,x);
}
int l=0,r=n;
while(l<=r){
int mid=l+r>>1;
if(check(mid))ans=mid,r=mid-1;
else l=mid+1;
}
// check(1);
printf("%d\n",ans);
return 0;
}