[bzoj2097][Usaco2010 Dec]Exercise 奶牛健美操

题目链接BZOJ2097

洛谷3000


简单抽象一下题意就是

去掉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.
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值