题目链接BZOJ2097
简单抽象一下题意就是
去掉n个结点的树上最多m条边,使得剩下的所有路径中最长值最小,求这个最小值。
以这样的问法出现,我们可以考虑二分答案法。
如果使最小值为x的方案存在,则使最小值为x+1的方案必然存在。
不存在同理。
所以很明显这题是具有二分性的。
然后就是如何判断方案的存在性 这里用到树形DP和贪心。
f[u]记录以u为深度最小点的链长度
也就是u到 以u为根的子树中 离它最远的叶子节点的路径长度
遍历过u为根的整棵子树之后,用a数组记录一下u每个的子结点的f[v]
对a从大到小排序,如果两条链长度和大于mid,则将长的一条截断
处理后新得到的最长值也就是f[u]的值
另外,由于dfs序遍历的括号化定理,
当我们处理u为根的子树的时候,已经保证其子结点为根的子树路径长符合要求。
奶牛们多好啊...
一路星移物换,我们没有散....
End.
{Beginner_df016}
var i,j,k,n,m,x,y,s,tot,anst,l,r,mid,ans:longint;
b,head,next:array[0..200007]of longint;
a,f:array[0..100007]of longint;
procedure add(x,y:longint);
begin
inc(tot);
b[tot]:=y;
next[tot]:=head[x];
head[x]:=tot;
end;
procedure qsort(l,r:longint);
var i,j,m,t:longint;
begin
i:=l; j:=r;
m:=a[(l+r) div 2];
repeat
while a[i]>m do inc(i);
while m>a[j] do dec(j);
if not(i>j) then
begin t:=a[i]; a[i]:=a[j]; a[j]:=t;
inc(i); dec(j); end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
procedure dfs(u,fa:longint);
var i,v,num:longint; p:boolean;
begin
f[u]:=0; p:=false;
i:=head[u];
while i<>0 do
begin
v:=b[i];
if v<>fa then
begin
p:=true;
dfs(v,u);
if f[v]+1>f[u] then f[u]:=f[v]+1;
end;
i:=next[i];
end;
if not p then begin f[u]:=0; exit; end;
num:=0;
i:=head[u];
while i<>0 do
begin
v:=b[i];
if v<>fa then begin inc(num); a[num]:=f[v]+1; end;
i:=next[i];
end;
qsort(1,num);
a[num+1]:=0;
for i:=1 to num do
if a[i]+a[i+1]>mid then begin inc(anst); a[i]:=0; end;
qsort(1,num);
f[u]:=a[1];
end;
function check:boolean;
begin
anst:=0;
dfs(1,0);
if anst>m then exit(false);
exit(true);
end;
begin
readln(n,m);
for i:=1 to n-1 do
begin
readln(x,y);
add(x,y);
add(y,x);
end;
l:=1; r:=n;
while l<=r do
begin
mid:=(l+r)>>1;
if check then begin ans:=mid; r:=mid-1; end
else l:=mid+1;
end;
writeln(ans);
end.