樹是一種優美的資料結構(嗯嗯,這句話看過百遍了)。
這道題目的描述很清晰,給你一顆N個點(N<10000)有邊權的無根樹,要你統計滿足距離不超過k的點對個數;
因為有多組資料的存在,所以平方的演算法是不行的,便向NlogN靠近(貌似用什麼NB資料結構可以O(N)?天啊。。)。
仔細分析了一下,其實是看了論文,對於每個滿足條件的點對,他們之間有一條路徑,對於每一個點,要麼在這個路徑上,要麼在路徑之外,這就讓我們想到了使用分治演算法:
對於每一顆樹,我們找到最優的這樣一個根,使得以他兒子為根的子樹中大小最大的最小。這樣選跟是有意義的,可以使得遞迴分下去的層數最少,這樣很容易證明分出的層數是小於等於logN層的(最壞情況一條鏈)。
我們找到這樣的根了,然後只要統計經過他的路徑的條數就可以了,條件就是dep(i)+dep(j)<=k (i和j屬於不同的子樹)—> dep(i)<=k-dep(j),我是利用treap統計的,好像可以O(N)的線性掃描,無解。
自己做完後,在遞迴到每顆子樹就可以了。因為一共有logN層,每層要NlogN的統計,所以複雜度是 N log2N 的,速度很快,300ms。
代碼自我感覺良好:
program poj1741;<br />var<br /> d,son,l,r,v,w,next,p,c,s,go:array[0..30000] of longint;<br /> o:array[0..20000] of boolean;<br /> n,len,best,i,min,t,tot,tmp,ans,root,a,b,cc:longint;</p><p>procedure left(var i:longint); begin<br /> tmp:=r[i];r[i]:=l[tmp];l[tmp]:=i;<br /> s[i]:=s[l[i]]+s[r[i]]+1;<br /> s[tmp]:=s[l[tmp]]+s[r[tmp]]+1;<br /> i:=tmp;<br />end;</p><p>procedure right(var i:longint); begin<br /> tmp:=l[i];l[i]:=r[tmp];r[tmp]:=i;<br /> s[i]:=s[l[i]]+s[r[i]]+1;<br /> s[tmp]:=s[l[tmp]]+s[r[tmp]]+1;<br /> i:=tmp;<br />end;</p><p>procedure insert(var i:longint;k:longint); begin<br /> if i=0 then begin<br /> inc(t);i:=t;<br /> s[i]:=1;<br /> w[i]:=k;<br /> v[i]:=random(maxlongint);<br /> l[i]:=0;r[i]:=0;<br /> end else<br /> if w[i]>k then begin<br /> insert(l[i],k);inc(s[i]);<br /> if v[l[i]]>v[i] then right(i);<br /> end else begin<br /> insert(r[i],k);inc(s[i]);<br /> if v[r[i]]>v[i] then left(i);<br /> end;<br />end;</p><p>function rank(i,k:longint):longint; begin<br /> if i=0 then exit(0);<br /> if w[i]<=k then rank:=s[l[i]]+1+rank(r[i],k) else<br /> rank:=rank(l[i],k);<br />end;</p><p>procedure link(a,b,cc:longint); begin<br /> inc(t);<br /> next[t]:=d[a];d[a]:=t;p[t]:=b;c[t]:=cc;<br />end;</p><p>procedure dfs1(fa,i,dep:longint);<br />var k,j:longint;<br />begin<br /> inc(ans,rank(root,len-dep));<br /> k:=d[i];j:=p[k];<br /> son[i]:=1;<br /> while k<>0 do begin<br /> if (j<>fa)and(not o[j]) then begin<br /> dfs1(i,j,dep+c[k]);<br /> inc(son[i],son[j]);<br /> end;<br /> k:=next[k];j:=p[k];<br /> end;<br />end;</p><p>procedure dfs2(fa,i,dep:longint);<br />var k,j,ms:longint;<br />begin<br /> insert(root,dep);<br /> ms:=tot-son[i];<br /> k:=d[i];j:=p[k];<br /> while k<>0 do begin<br /> if (j<>fa)and(not o[j]) then begin<br /> dfs2(i,j,dep+c[k]);<br /> if son[j]>ms then ms:=son[j];<br /> end;<br /> k:=next[k];j:=p[k];<br /> end;<br /> if ms<min then begin<br /> min:=ms;best:=i;<br /> end;<br />end;</p><p>procedure deal(i:longint);<br />var k,j:longint;<br />begin<br /> o[i]:=true;<br /> root:=0;t:=0;<br /> insert(root,0);<br /> k:=d[i];j:=p[k];<br /> while k<>0 do begin<br /> if not o[j] then begin<br /> min:=maxlongint;<br /> dfs1(i,j,c[k]);tot:=son[j];<br /> dfs2(i,j,c[k]);go[j]:=best;<br /> end;<br /> k:=next[k];j:=p[k];<br /> end;<br /> k:=d[i];j:=p[k];<br /> while k<>0 do begin<br /> if not o[j] then deal(go[j]);<br /> k:=next[k];j:=p[k];<br /> end;<br />end;</p><p>begin<br /> readln(n,len);<br /> randomize;<br /> while n<>0 do begin<br /> t:=0;ans:=0;<br /> fillchar(o,sizeof(o),false);<br /> fillchar(d,sizeof(d),0);<br /> for i:=1 to n-1 do begin<br /> readln(a,b,cc);<br /> link(a,b,cc);link(b,a,cc);<br /> end;<br /> deal(1);<br /> writeln(ans);<br /> readln(n,len);<br /> end;<br />end.<br />