zoukankan      html  css  js  c++  java
  • bzoj3124

    很好的一道treedp,当然也挺烦的
    首先不难想到先求出一个直径,然后穷举每条边,看他删除之后直径大小是否会变,变了的话就是必须经过的边
    下面我们就要想怎么优化,本人语言表达略差,还是配合程序说吧。

      1 type node=record
      2        point,next:longint;
      3        cost:int64;
      4      end;
      5 
      6 var f:array[0..200010] of int64;
      7     pr,fr:array[0..200010,0..2] of longint;
      8     g,h:array[0..200010,0..2] of int64;
      9     p:array[0..200010] of longint;
     10     edge:array[0..400010] of node;
     11     v:array[0..200010] of boolean;
     12     i,n,len,ans,x,y,z:longint;
     13 
     14 procedure add(x,y,z:longint);
     15   begin
     16     inc(len);
     17     edge[len].point:=y;
     18     edge[len].cost:=z;
     19     edge[len].next:=p[x];
     20     p[x]:=len;
     21   end;
     22 
     23 function max(a,b:int64):int64;
     24   begin
     25     if a>b then exit(a) else exit(b);
     26   end;
     27 
     28 procedure dp(x:longint);
     29   var i,y:longint;
     30   begin
     31     i:=p[x];
     32     v[x]:=true;
     33     while i<>-1 do
     34     begin
     35       y:=edge[i].point;
     36       if not v[y] then
     37       begin
     38         dp(y);
     39         f[x]:=max(f[x],f[y]);  //f[]表示以x为根的子树中最长的路径长
     40         if g[y,0]+edge[i].cost>g[x,0] then  //维护以x为根走到底最长的3条路径(显然不能有两条路径经过同一个孩子)
     41 //这里要维护3条,因为要考虑删边的时候碰巧干掉了其中一条,如果单纯求树的直径的时候只要维护最长和次长即可)
     42         begin
     43           g[x,2]:=g[x,1];
     44           fr[x,2]:=fr[x,1];
     45           g[x,1]:=g[x,0];
     46           fr[x,1]:=fr[x,0];
     47           g[x,0]:=g[y,0]+edge[i].cost;
     48           fr[x,0]:=y;  //从哪转移来的
     49         end
     50         else if (g[y,0]+edge[i].cost>g[x,1]) then
     51         begin
     52           g[x,2]:=g[x,1];
     53           fr[x,2]:=fr[x,1];
     54           g[x,1]:=g[y,0]+edge[i].cost;
     55           fr[x,1]:=y;
     56         end
     57         else if (g[y,0]+edge[i].cost>g[x,2]) then
     58         begin
     59           g[x,2]:=g[y,0]+edge[i].cost;
     60           fr[x,2]:=y;
     61         end;
     62         if f[y]>h[x,0] then  //h维护的是以x为根的子树中最长的2条路径(不经过根)
     63         begin
     64           h[x,1]:=h[x,0];
     65           pr[x,1]:=pr[x,0];
     66           h[x,0]:=f[y];
     67           pr[x,0]:=y;  //从哪转移来的
     68         end
     69         else if f[y]>h[x,1] then
     70         begin
     71           h[x,1]:=f[y];
     72           pr[x,1]:=y;
     73         end;
     74       end;
     75       i:=edge[i].next;
     76     end;
     77     f[x]:=max(f[x],g[x,1]+g[x,0]);
     78   end;
     79 
     80 procedure dfs(x:longint;l,d:int64); //l表示以x为终点且不是起点x的后辈的最长路径,d表示之前搜索到的不经过x的最长路径
     81   var i,y:longint;
     82       l1,l2,l3:int64;
     83   begin
     84     i:=p[x];
     85     v[x]:=true;
     86     while i<>-1 do
     87     begin
     88       y:=edge[i].point;
     89       if not v[y] then   //大批的分类讨论
     90       begin
     91         l1:=f[y];
     92         if y=pr[x,0] then l2:=h[x,1]
     93         else l2:=h[x,0];
     94         l2:=max(l2,d);
     95 
     96         if y=fr[x,0] then l2:=max(l2,g[x,1]+g[x,2])
     97         else if y=fr[x,1] then l2:=max(l2,g[x,0]+g[x,2])
     98         else l2:=max(l2,g[x,0]+g[x,1]);
     99 
    100         if y=fr[x,0] then l3:=g[x,1]
    101         else l3:=g[x,0];
    102         l2:=max(l2,l+l3);
    103         if max(l1,l2)<f[1] then inc(ans);
    104         dfs(y,max(l3,l)+edge[i].cost,l2);
    105       end;
    106       i:=edge[i].next;
    107     end;
    108   end;
    109 
    110 begin
    111   readln(n);
    112   fillchar(p,sizeof(p),255);
    113   for i:=1 to n-1 do
    114   begin
    115     readln(x,y,z);
    116     add(x,y,z);
    117     add(y,x,z);
    118   end;
    119   dp(1);
    120   writeln(f[1]);
    121   fillchar(v,sizeof(v),false);
    122   ans:=0;
    123   dfs(1,0,0);
    124   writeln(ans);
    125 end.
    View Code
  • 相关阅读:
    LeetCode 24. Swap Nodes in Pairs (两两交换链表中的节点)
    LeetCode 1041. Robot Bounded In Circle (困于环中的机器人)
    LeetCode 1037. Valid Boomerang (有效的回旋镖)
    LeetCode 1108. Defanging an IP Address (IP 地址无效化)
    LeetCode 704. Binary Search (二分查找)
    LeetCode 744. Find Smallest Letter Greater Than Target (寻找比目标字母大的最小字母)
    LeetCode 852. Peak Index in a Mountain Array (山脉数组的峰顶索引)
    LeetCode 817. Linked List Components (链表组件)
    LeetCode 1019. Next Greater Node In Linked List (链表中的下一个更大节点)
    29. Divide Two Integers
  • 原文地址:https://www.cnblogs.com/phile/p/4473142.html
Copyright © 2011-2022 走看看