• BZOJ1912:[APIO2010]patrol巡逻


    Description

    Input

    第一行包含两个整数 n, K(1 ≤ K ≤ 2)。接下来 n – 1行,每行两个整数 a, b, 表示村庄a与b之间有一条道路(1 ≤ a, b ≤ n)。

    Output

    输出一个整数,表示新建了K 条道路后能达到的最小巡逻距离。

    Sample Input

    8 1
    1 2
    3 1
    3 4
    5 3
    7 5
    8 5
    5 6

    Sample Output

    11

    HINT

    10%的数据中,n ≤ 1000, K = 1; 
    30%的数据中,K = 1; 
    80%的数据中,每个村庄相邻的村庄数不超过 25; 
    90%的数据中,每个村庄相邻的村庄数不超过 150; 
    100%的数据中,3 ≤ n ≤ 100,000, 1 ≤ K ≤ 2。

     
    题解:
    对于新建的k条边,求出在原树上的k条路径;若其无重复边,则优化长度为路径长度和;若有重复,则重复部分不被优化,优化的部分也可以表示为两条不重复路径。
    问题变成了在树上求k条边不重复路径,使总距离最长。
    若k=1,则该路径为树的直径;
    若k=2,可以证明,两条路径只有两种可能:
    1.一条为直径,一条与直径无重复。
    2.两条都与直径有重复。
    这样,只要先求一次直径,将直径上的边权值赋为-1,再求一次直径,将结果相加即可。
     
    代码:
     1 type
     2   point=^node;
     3    node=record
     4       x,v:longint; next:point;
     5    end;
     6 var
     7   a:array[0..100000]of point;
     8   f1,f2,s1,s2:array[0..100000]of longint;
     9   n,i,m,max,k,x,y,ans:longint; p:point;
    10 procedure ss(x,e:longint);
    11 var p:point;
    12     y:longint;
    13 begin
    14   s1[x]:=x; s2[x]:=x;
    15   new(p); p:=a[x];
    16   while p<>nil do
    17   begin
    18     y:=p^.x;
    19     if y=e then begin p:=p^.next; continue; end;
    20     ss(y,x);
    21     if f1[y]+p^.v>f1[x] then
    22     begin
    23       f2[x]:=f1[x]; s2[x]:=s1[x];
    24       f1[x]:=f1[y]+p^.v; s1[x]:=y;
    25     end else
    26     if f1[y]+p^.v>f2[x] then
    27     begin
    28       f2[x]:=f1[y]+p^.v; s2[x]:=y;
    29     end;
    30     p:=p^.next;
    31   end;
    32   if f1[x]+f2[x]>f1[max]+f2[max] then
    33   max:=x;
    34 end;
    35 procedure add(x,y:longint);
    36 var p:point;
    37 begin
    38   new(p); p^.x:=y; p^.v:=1; p^.next:=a[x]; a[x]:=p;
    39 end;
    40 procedure qq(x:longint);
    41 var 
    42   p:point; 
    43   y:longint;
    44 begin
    45   new(p); p:=a[x];
    46   while p<>nil do
    47    begin
    48      y:=p^.x;
    49      if y=s1[x] then begin p^.v:=-1; qq(y); break; end;
    50      p:=p^.next;
    51    end;
    52 end;
    53 begin
    54   readln(n,k);
    55   for i:=1 to n-1 do
    56    begin
    57      readln(x,y); add(x,y);  add(y,x);
    58    end;
    59   ans:=2*(n-1); max:=0; f1[0]:=0; f2[0]:=0;
    60   ss(1,0);
    61   ans:=ans-f1[max]-f2[max]+1;
    62   if k=1 then writeln(ans) else
    63   begin
    64     fillchar(f1,sizeof(f1),0);
    65     fillchar(f2,sizeof(f2),0);
    66     new(p); p:=a[max];
    67     while p<>nil do
    68     begin
    69       y:=p^.x;
    70       if (y=s1[max])or(y=s2[max]) then p^.v:=-1;
    71       p:=p^.next;
    72     end;
    73     qq(s1[max]); qq(s2[max]);  max:=0;
    74     ss(1,0);
    75     ans:=ans-f1[max]-f2[max]+1;
    76     writeln(ans);
    77   end;
    78 end.
    View Code
  • 相关阅读:
    Merge into使用详解( 同时执行inserts和updates操作 )
    sql执行计划解析案例(二)
    包的定义和导入-----package
    jQuery练习实例(四)
    打印沙漏形
    Java的RandomAccessFile
    农场有头大母牛,每年生头小母牛,小母牛五年后生小母牛,问20年后农场一共有多少头牛?(用面向对象的思想)
    关于编译Lambda时报告返回的为void的错误
    银行对账
    mysql查询随机几条数据(速度快)
  • 原文地址:https://www.cnblogs.com/GhostReach/p/6293713.html
Copyright © 2020-2023  润新知