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
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.