日常训练 20161102 隔离区

4 篇文章 0 订阅
3 篇文章 0 订阅
题意简述:给出一个 n 个点的树(有边权),问删除其中一条边,剩下最长链的长度的期望。(乘n1输出)
题解:经典树形dp,用down1、down2、down3记录每个点向下的第一第二第三长链,up记录每个点向上最长链,son1、son2记录每个点有第一第二长链的两棵子树,dis记每个点到其父亲的边权,down_ans记录每个点向下的答案,lws是longest_without_subtree,是动态修改的,lws[x]记录对于枚举的当前x的一个儿子y,不包含y这棵子树的最长路。对于一个点,只要down_ans和lws取个max即可。
代码丑,不要看。。
type
  edge=record
         y,v,next:longint;
       end;
  rec=record
        x:longint;
        v:int64;
      end;
const
  MAXN=500050;
var
  map:array[0..MAXN * 2] of edge;
  down1,down2,down3,son1,son2:array[0..MAXN] of rec;
  down_ans,up,lws:array[0..MAXN] of int64;
  first,dis:array[0..MAXN] of longint;
  s:longint;
  ans:int64;
function max(a,b:int64):int64;
  begin if (a>b) then exit(a) else exit(b); end;
procedure swap(var a,b:int64);
  var t:int64;
  begin t:=a;a:=b;b:=t; end;
procedure ins(x,y,v:longint);
  begin
    inc(s);map[s].y:=y;map[s].v:=v;
    map[s].next:=first[x];first[x]:=s;
  end;
procedure init;
  var
    n,i,x,y,v:longint;
  begin
    read(n);ans:=0;
    for i:=1 to n-1 do
      begin
        read(x,y,v);
        ins(x,y,v);
        ins(y,x,v);
      end;
  end;
procedure dfs1(x,f:longint);
  var
    t,y,v:longint;
  begin
    t:=first[x];
    while (t>0) do
      begin
        y:=map[t].y;v:=map[t].v;
        if (y<>f) then
          begin
            dfs1(y,x);dis[y]:=map[t].v;
            if (down1[y].v+v>=down1[x].v)
              then
                begin
                  down3[x]:=down2[x];
                  down2[x]:=down1[x];
                  down1[x].x:=y;
                  down1[x].v:=down1[y].v+v;
                end
              else
                if (down1[y].v+v>=down2[x].v)
                  then
                    begin
                      down3[x]:=down2[x];
                      down2[x].x:=y;
                      down2[x].v:=down1[y].v+v;
                    end
                  else
                    if (down1[y].v+v>down3[x].v) then
                      begin
                        down3[x].x:=y;
                        down3[x].v:=down1[y].v+v;
                      end;
            if (down_ans[y]>=son1[x].v)
              then
                begin
                  son2[x]:=son1[x];
                  son1[x].x:=y;
                  son1[x].v:=down_ans[y];
                end
              else
                if (down_ans[y]>son2[x].v) then
                  begin
                    son2[x].x:=y;
                    son2[x].v:=down_ans[y];
                  end;
            down_ans[x]:=max(down_ans[x],down_ans[y]);
          end;
        t:=map[t].next;
      end;
    down_ans[x]:=max(down_ans[x],down1[x].v+down2[x].v);
  end;
procedure dfs2(x,f:longint);
  var
    t:longint;
  begin
    t:=first[x];
    if (x=1)
      then up[x]:=0
      else
        begin
          if (down1[f].x=x)
            then up[x]:=down2[f].v
            else up[x]:=down1[f].v;
          up[x]:=max(up[x],up[f]);
          inc(up[x],dis[x]);
        end;
    while (t>0) do
      begin
        if (map[t].y<>f)
          then dfs2(map[t].y,x);
        t:=map[t].next;
      end;
  end;
procedure dfs3(x,f:longint);
  var
    t,y:longint;
    t1,t2,t3:int64;
  begin
    t:=first[x];
    if (x<>1) then ans:=ans+max(down_ans[x],lws[f]);
    while (t>0) do
      begin
        y:=map[t].y;
        if (y<>f) then
          begin
            if (down1[x].x=y)
              then begin t1:=down2[x].v;t2:=down3[x].v;end
              else if (down2[x].x=y)
                     then begin t1:=down1[x].v;t2:=down3[x].v;end
                     else begin t1:=down1[x].v;t2:=down2[x].v;end;
            t3:=up[x];
            if (t1<t3) then swap(t1,t3);
            if (t2<t3) then swap(t2,t3);
            if (son1[x].x=y)
              then lws[x]:=max(son2[x].v,lws[f])
              else lws[x]:=max(son1[x].v,lws[f]);
            lws[x]:=max(lws[x],t1+t2);
            dfs3(y,x);
          end;
        t:=map[t].next;
      end;
  end;
begin
  assign(input,'split.in');reset(input);
  assign(output,'split.out');rewrite(output);
  init;
  dfs1(1,0);
  dfs2(1,0);
  dfs3(1,0);
  writeln(ans);
  close(input);close(output);
end.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值