这道题是楼教主《男人八题》中的一题,算法:树的分治。
看到题目时很容易想到直接Dfs,但那样的话时间复杂度会高达O(n^2)!对于n<=40000的数据来说根本无法承受。所以,必须考虑分治的思想。
怎么分治呢?
树的重心!
至于树的重心,不熟悉的OIer可以做掉POJ1655,或者NOI2011 Day2的第一题来练手,这两道题要求的就是树的重心。至于pascal语言的ACMer可以考虑编译开关,OIer最好不要加编译开关,练一练非递归手写栈也是不错的。
基本思路:
1、把这棵无根树以1为根节点,使其变成一棵有根树。
2、对于每棵现在要处理的树,进行如下处理:
(1)遍历这棵树,找到所有一端点为根,路径长度<=k的路径总数
(2)通过(1)求出的结果求和计算出所有长度<=k的的路径总数
(3)去重:也就是删去(2)中计算有重合的路径部分
(4)找到这棵子树的重心,递归处理这棵子树,也就是重复步骤2
3、统计答案并输出
总体来说,这题难度不小,可是把它做掉的感觉也是很cool的。最重要的是,树的分治思想在这道题中体现得淋漓尽致,这是这道题的借鉴意义所在。
POJ1741也是这个思想,可以拿来练手。
CODE
Program POJ1987;//By_Poetshy Const maxn=40005; Var i,j,k,m,n,d,kol :Longint; sum,root,min,tot,ans :Longint; pre,other,last,data :Array[0..maxn*2]of Longint; seq :Array[0..maxn*2]of Longint; size,f :Array[0..maxn*2]of Longint; v :Array[0..maxn]of Boolean; Procedure Getroot(i:Longint); var j,k,w:Longint; begin j:=last[i]; size[i]:=1; v[i]:=true; w:=0; while j<>0 do begin k:=other[j]; if not v[k] then begin Getroot(k); inc(size[i],size[k]); if size[k]>w then w:=size[k]; end; j:=pre[j]; end; if sum-size[i]>w then w:=sum-size[i]; if w<min then begin min:=w; root:=i; end; v[i]:=false; end; Procedure Count(i:Longint); var j,k:Longint; begin v[i]:=true; j:=last[i]; inc(sum); while j<>0 do begin k:=other[j]; if not v[k] then Count(k); j:=pre[j]; end; v[i]:=false; end; Procedure Deal(i,d:Longint); var j,k:Longint; begin if d<=kol then begin inc(tot); seq[tot]:=d; end else exit; v[i]:=true; j:=last[i]; while j<>0 do begin k:=other[j]; if not v[k] then Deal(k,d+data[j]); j:=pre[j]; end; v[i]:=false; end; Procedure Qsort(l,r:Longint); var i,j,k,temp:Longint; begin if l>=r then exit; i:=l;j:=r;k:=seq[(i+j)>>1]; repeat while seq[i]<k do inc(i); while seq[j]>k do dec(j); if i<=j then begin temp:=seq[i]; seq[i]:=seq[j]; seq[j]:=temp; inc(i);dec(j); end; until i>j; if i<r then Qsort(i,r); if l<j then Qsort(l,j); end; Function Reduce(l,r:Longint):Longint; var i,j:Longint; begin Reduce:=0; j:=r; for i:=l to r do begin if i=j then exit; while (i<j)and(seq[i]+seq[j]>kol)do dec(j); if i=j then exit; inc(Reduce,j-i); end; end; Procedure Dfs(i:Longint); var y,j,k,la:Longint; begin sum:=0;tot:=1;seq[tot]:=0; Count(i); if sum=1 then exit; min:=sum; Getroot(i); i:=root;j:=last[i]; v[i]:=true; while j<>0 do begin k:=other[j]; if not v[k] then begin la:=tot+1; Deal(k,data[j]); Qsort(la,tot); dec(f[i],Reduce(la,tot)); end; j:=pre[j]; end; Qsort(1,tot); inc(f[i],Reduce(1,tot)); j:=last[i]; while j<>0 do begin k:=other[j]; if not v[k] then Dfs(k); j:=pre[j]; end; v[i]:=false; end; BEGIN readln(n); for i:=1 to n-1 do begin readln(m,j,d); inc(k);pre[k]:=last[m];last[m]:=k;other[k]:=j;data[k]:=d; inc(k);pre[k]:=last[j];last[j]:=k;other[k]:=m;data[k]:=d; end; readln(kol); Dfs(1); ans:=0; for i:=1 to n do inc(ans,f[i]); writeln(ans); END.