POJ1987 Distance Statistics——树的分治

 

这道题是楼教主《男人八题》中的一题,算法:树的分治。

看到题目时很容易想到直接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也是这个思想,可以拿来练手。

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.  

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值