I and OI
Past...

题意:最多去掉一个树上的s条边,将树分割成S+1块,使得所有块的最长链的最大值最小.

USACO官方的题解讲的很清楚..

First, conduct a binary search on the answer, D. To do this, just find a way to check, for any D, if it is possible to make S cuts such that each tree has diameter at most D.

We will give a greedy algorithm which will compute the smallest number of cuts needed if each subtree is to have diameter at most D.

Root the tree arbitrarily.

Suppose we are processing a vertex A with children C1, C2, ..., Ck, and suppose that any necessary cuts have been made to edges below these k vertices. Let the depth of a vertex be the maximum length from that vertex down to a leaf.

The diameter of the subtree rooted at A is the maximum of depth(Ci) + depth(Cj) + 2, over all distinct i and j, if the maximal diameter goes through A, or the diameter of the subtree rooted at Ci for some i. Since we are assuming all lower cuts have been made, we actually just need to ensure that depth(Ci) + depth(Cj) + 2 is at most D.

If it is at most D, then there is certainly no reason to make any more cuts within this tree. If it is greater than D, then we need to cut off some edges between A and its children. We want to cut off children of maximum depth (because given a choice between cutting off two vertices, it is always better to cut off the one which would contribute the most to a large diameter), and we cut off children until the maximum value of depth(Ci) + depth(Cj) + 2 is at most D.

Perform a depth first search through the tree, and for each node, process its children before processing itself.

Meanwhile, keep track of the total number of cuts and then check if this value is less than or equal to S. This algorithm is O(n log2 n). One log factor is for the binary search, the n factor is for traversing the tree, and another log factor is for sorting the depths of a nodes children.

Notice how this second log factor is in fact very small, since most nodes will have a small number of children. (In fact, if you are careful enough, you can cut off this extra log factor entirely.)

code:

/************************************************************** 
    Problem: 2097
    User: exponent 
    Language: Pascal 
    Result: Accepted 
    Time:732 ms 
    Memory:7280 kb 
****************************************************************/ 
  
{$M 10000000}
type  edge=record
      v,n:longint; 
end; 
const maxn=100001; 
      maxm=200001; 
var   ex:array[0..maxm] of edge; 
      e:array[0..maxn] of edge; 
      head,headx,h,d:array[0..maxn] of longint; 
      vis:array[0..maxn] of boolean; 
      n,s,i,u,v,l,r,mid,cnt,cntx,size,count:longint; 
  
      procedure add(u,v:longint); 
      begin
            inc(cnt); 
            e[cnt].v:=v; 
            e[cnt].n:=head[u]; 
            head[u]:=cnt; 
      end; 
  
      procedure addx(u,v:longint); 
      begin
            inc(cntx); 
            ex[cntx].v:=v; 
            ex[cntx].n:=headx[u]; 
            headx[u]:=cntx; 
      end; 
  
      procedure buildtree(u:longint); 
      var   v,p:longint; 
      begin
            vis[u]:=true; 
            p:=headx[u]; 
            while p<>0 do
            begin
                  v:=ex[p].v; 
                  if not vis[v] then
                  begin
                        add(u,v); 
                        buildtree(v); 
                  end; 
                  p:=ex[p].n; 
            end; 
      end; 
  
      procedure swap(a,b:longint); 
      var   temp:longint; 
      begin
            temp:=h[a]; 
            h[a]:=h[b]; 
            h[b]:=temp; 
      end; 
  
      procedure down(k:longint); 
      var   p:longint; 
      begin
            while k<=size>>1 do
            begin
                  p:=k<<1; 
                  if (p<size)and(h[p]<h[p+1]) then inc(p); 
                  if h[k]<h[p] then
                    begin swap(k,p); k:=p; end
                  else break; 
            end; 
      end; 
  
      procedure up(k:longint); 
      begin
            while (k>1)and(h[k>>1]<h[k]) do
            begin swap(k,k>>1); k:=k>>1; end; 
      end; 
  
      procedure ins(new:longint); 
      begin
            inc(size); 
            h[size]:=new; 
            up(size); 
      end; 
  
      procedure del(k:longint); 
      begin
            swap(k,size); 
            dec(size); 
            down(k); 
      end; 
  
      function gettop:longint; 
      begin
            gettop:=h[1]; 
            del(1); 
      end; 
  
      procedure dfs(u,lim:longint); 
      var   v,p,c,top:longint; 
      begin
            p:=head[u]; 
            while p<>0 do
            begin
                  v:=e[p].v; 
                  dfs(v,lim); 
                  p:=e[p].n; 
            end; 
            size:=0; 
            p:=head[u]; 
            while p<>0 do
            begin
                  v:=e[p].v; 
                  ins(d[v]); 
                  p:=e[p].n; 
            end; 
            if size=0 then
            begin d[u]:=0; exit; end; 
            if size=1 then
            begin
                  if h[1]>=lim then
                    begin d[u]:=0; inc(count); end
                  else d[u]:=h[1]+1; 
                  exit; 
            end; 
            while size>=2 do
            begin
                  top:=gettop; 
                  if top+h[1]+2>lim then inc(count) 
                  else
                  begin ins(top); break; end; 
            end; 
            if h[1]>=lim then inc(count) 
            else d[u]:=h[1]+1; 
      end; 
  
  
      function check(middle:longint):boolean; 
      begin
            fillchar(d,sizeof(d),0); 
            count:=0; 
            dfs(1,middle); 
            exit(count<=s); 
      end; 
  
begin
      readln(n,s); 
      for i:=1 to n do
      begin
            readln(u,v); 
            addx(u,v); 
            addx(v,u); 
      end; 
      buildtree(1); 
  
      l:=0; r:=maxn; 
      while l<r do
      begin
            mid:=(l+r)>>1; 
            if check(mid) then r:=mid 
            else l:=mid+1; 
      end; 
      writeln(l); 
end.
posted on 2011-08-14 15:44  exponent  阅读(354)  评论(0编辑  收藏  举报