JZOJ 4715 【NOIP2016提高A组模拟8.19】树上路径

树上路径

题目大意

给出一棵树,求出最小的 k ,使得,且在树中存在路径p,使得 k >=S k <=E。( k 为路径p上的边的权值和)

数据范围

n <=105 , E -S<= 106 E ,S<= 109

题解

这一题显然 就是点分治。
以下是一道点分治的经典例题,可以看一下我写的 blog :树中点对距离

在对一棵子树计算答案的时候,算出重心并求出树中所有的点到重心的距离,计入 dis 数组,并排序, 维护两个指针计算答案即可。
但我们要注意一个细节,用来更新答案的两个点不能是同一棵子树的,所以当我们发现指针 i j所指的两个点为同一棵子树时,我们需找到 j 后面第一个和i不同子树的点,这个我们可以预处理出来。

算完后按照重心对当前子树分治下去即可。

Code(Pascal)

const
    zd=20;
var
    n,s,e,i,j,k,l,o,p,xd,cqy:longint;
    ans,kk:int64;
    bz:array[0..120000] of boolean;
    bj:array[0..300000,1..3] of longint;
    px:array[0..120000,1..2] of longint;
    en,fa,sd,ph,qz,size:array[0..120000] of longint;
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 min(a,b:int64):int64;
    begin
        if a<b then exit(a)
        else exit(b);
    end;
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;
function bl(o,dd:longint):longint;
    var
        i,r,ooo: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;
            r:=bl(bj[i,2],dd);
            if r>0 then exit(r);
            size[o]:=size[o]+size[bj[i,2]];
        end;
        if size[o]>=dd-size[o] then exit(o);
        exit(0);
    end;
procedure lfsb(o,cq,qy:longint);
    var
        i: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;
            lfsb(bj[i,2],cq+bj[i,3],qy);
            size[o]:=size[o]+size[bj[i,2]];
        end;
    end;
procedure dg(o,p:longint);
    var
        i,j,k,l:longint;
    begin
        inc(xd);
        ph[o]:=xd;
        k:=bl(o,p);
        cqy:=0;
        bz[k]:=false;
        inc(xd);
        ph[k]:=xd;
        for i:=en[k-1]+1 to en[k] do
        if bz[bj[i,2]] then
        begin
            ph[bj[i,2]]:=xd;
            lfsb(bj[i,2],bj[i,3],i-en[k-1]);
        end;
        qsortpx(1,cqy);
        qz[cqy]:=0;
        px[0,1]:=maxlongint div 2;
        for i:=cqy-1 downto 1 do
        if px[i,2]=px[i+1,2] then qz[i]:=qz[i+1]
        else qz[i]:=i+1;
        i:=0;
        j:=cqy;
        while i+1<j do
        begin
            inc(i);
            while (px[i,1]+px[j-1,1]>=s) and (j>i+1) do dec(j);
            if i>=j then break;
            if px[i,1]+px[j,1]<s then continue;
            if px[i,2]<>px[j,2] then ans:=min(ans,px[i,1]+px[j,1])
            else ans:=min(ans,px[i,1]+px[qz[j],1]);
        end;
        for i:=1 to cqy do
        if px[i,1]>=s then ans:=min(ans,px[i,1]);
        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,s,e);
    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);
    sd[0]:=-1;
    sd[1]:=1;
    ans:=e+1;
    for i:=1 to n do
    bz[i]:=true;
    dg(1,n);
    if ans>e then writeln(-1)
    else writeln(ans);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值