树中点对距离
题目大意
给出一棵带边权的树,问有多少对点的距离<= Len
数据范围
2
<=
题解
这是一道十分经典的点分治题目。
点分治,顾名思义,就是按照点来分治。
假设当前要计算某棵子树里面满足题目条件的点对数,我们可以先找出这棵子树的重心。
易知,此棵子树的点对数=经过重心的合法点对数+不经过重心的合法点对数。
我们先求经过重心的合法点对数,计算出此子树里面所有的点到重心的距离,计入数组
dis
,然后排序。计算这颗子树的答案时,维护两个指针
i
,
可以证明,
我们就可以借此求出答案,循环终止条件为
大概代码如下:
i:=0;
j:=m; // dis数组的长度为m
while i<j do
begin
inc(i);
while dis[i]+dis[j]>len do dec(j);
if i>=j then break;
ans:=ans+(j-i);
end;
但我们会发现,这样做的话答案会
于是我们求答案时需要多维护一个数组把同一棵子树的非法点对减掉,这样就可以了。
找完经过重心的点对答案后,就剩不经过重心的合法点对数,然后我们按照重心把此棵子树分成多棵子树,分治下去,对分出来的子树执行上述操作统计答案即可。
Code(Pascal)
var
bz:array[0..12000] of boolean;
en,ph,size,qz:array[0..12000] of longint;
px:array[0..20000,1..2] of int64;
bj:array[0..20000,1..3] of longint;
len,n,m,j,k,l,i,o,p,cqy,xd,ans:longint;
procedure qsortpx(l,r:longint);
var
i,j,m:longint;
begin
i:=l;
j:=r;
m:=px[(l+r) div 2,1];
repeat
while px[i,1]<m do inc(i);
while px[j,1]>m do dec(j);
if i<=j then
begin
px[0]:=px[i];
px[i]:=px[j];
px[j]:=px[0];
inc(i);
dec(j);
end;
until i>j;
if l<j then qsortpx(l,j);
if i<r then qsortpx(i,r);
end;
procedure qsort(l,r:longint);
var
i,j,m:longint;
begin
i:=l;
j:=r;
m:=bj[(l+r) div 2,1];
repeat
while bj[i,1]<m do inc(i);
while bj[j,1]>m do dec(j);
if i<=j then
begin
bj[0]:=bj[i];
bj[i]:=bj[j];
bj[j]:=bj[0];
inc(i);
dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
function bl(o,dx:longint):longint;
var
i:longint;
begin
size[o]:=1;
for i:=en[o-1]+1 to en[o] do
if bz[bj[i,2]] and (ph[bj[i,2]]<>xd) then
begin
ph[bj[i,2]]:=xd;
bl:=bl(bj[i,2],dx);
if bl>0 then exit;
size[o]:=size[o]+size[bj[i,2]];
end;
if size[o]>=dx-size[o] then exit(o);
exit(0);
end;
procedure cqyilo(o,cq,qy:longint);
var
i,j,k:longint;
begin
inc(cqy);
px[cqy,1]:=cq;
px[cqy,2]:=qy;
size[o]:=1;
for i:=en[o-1]+1 to en[o] do
if bz[bj[i,2]] and (ph[bj[i,2]]<>xd) then
begin
ph[bj[i,2]]:=xd;
cqyilo(bj[i,2],cq+bj[i,3],qy);
size[o]:=size[o]+size[bj[i,2]];
end;
end;
procedure dg(o,dd:longint);
var
i,j,l,k,p:longint;
begin
inc(xd);
k:=bl(o,dd);
bz[k]:=false;
cqy:=0;
inc(xd);
for i:=en[k-1]+1 to en[k] do
if bz[bj[i,2]] then
begin
ph[bj[i,2]]:=xd;
cqyilo(bj[i,2],bj[i,3],i-en[k-1]);
qz[i-en[k-1]]:=size[bj[i,2]];
end;
qsortpx(1,cqy);
for i:=1 to cqy do
if px[i,1]<=len then inc(ans)
else break;
i:=0;
j:=cqy;
px[0,1]:=-maxlongint;
while i<j do
begin
inc(i);
dec(qz[px[i,2]]);
while px[i,1]+px[j,1]>len do
begin
dec(qz[px[j,2]]);
dec(j);
end;
if i>=j then break;
ans:=ans+(j-i-qz[px[i,2]]);
end;
for i:=en[k-1]+1 to en[k] do
if (size[bj[i,2]]>1) and bz[bj[i,2]] then
dg(bj[i,2],size[bj[i,2]]);
end;
begin
readln(n,len);
for i:=1 to n-1 do
begin
readln(bj[i*2-1,1],bj[i*2-1,2],bj[i*2-1,3]);
bj[i*2,1]:=bj[i*2-1,2];
bj[i*2,2]:=bj[i*2-1,1];
bj[i*2,3]:=bj[i*2-1,3];
inc(en[bj[i*2,1]]);
inc(en[bj[i*2,2]]);
end;
for i:=1 to n do
en[i]:=en[i-1]+en[i];
qsort(1,2*n-2);
for i:=1 to n do
bz[i]:=true;
dg(1,n);
writeln(ans);
end.