【NOIP2016练习】T2 旅行(树形DP,换根)

题意:小C上周末和他可爱的同学小A一起去X湖玩。
X湖景区一共有n个景点,这些景点由n-1条观光道连接着,从每个景点开始都可以通过观光道直接或间接地走到其他所有的景点。小C带着小A从1号景点开始游玩。游览完第一个景点后,先由小C决定下一个游览的景点,他们一起走去那个景点玩。接下来,他们轮流决定他们下一步去哪个景点玩。他们不会选择已经走过的景点,因为重复游览一个景点是无趣的。当他们无法选择下一个景点时,他们就结束旅程。
小C是好动的男孩纸,所以他希望游览的过程尽量长,也就是走过观光道的长度和最大。而小A是文静的女孩纸,她希望游览的过程尽量短。小A和小C都极度聪明,且他们的目光都足够长远,他们做出的决策都是对自己最优的。由于小C在旅游前就仔细研究了X湖景区的地图,他可以在旅行开始前就用自己惊人的数学能力推算出他和小A旅行的路径长度。
小C的梦境是美好的。在他的梦里,他和小A又进行了n-1次旅行,第i次旅行从i+1号点开始,每次也是小C先决定下一个景点,然后小A,然后小C……直到旅行结束。现在小C希望你对于所有n次旅行,求出他和小A旅行的路径长度。

对于100%的数据,N ≤ 300000, c[i] ≤ 1e9

对于60%的数据,N ≤ 3000

思路:对于60分,容易想到枚举根,做N次O(N)的DP,时间复杂度O(n)

        对于100分,模拟样例后发现两个直接相连的节点U与V,其DP值只有U与V点时不同,所以考虑当根从U到V时O(1)转移求出新的DP[u]与DP[v]

        注意此处不需要保证整个DP数组值都为正确,只要U的值与V的值正确即可

        可以想到当U的最值由V转移时,两者交换后V必须从U的另一支转移,所以记录次值

        调参大法好

        

  1 var f:array[1..300000,1..4]of int64;
  2     ans:array[1..300000]of int64;
  3     head,vet,next,len,flag:array[1..600000]of longint;
  4     n,tot,i,x,y,z:longint;
  5     oo:int64;
  6 
  7 procedure add(a,b,c:longint);
  8 begin
  9  inc(tot);
 10  next[tot]:=head[a];
 11  vet[tot]:=b;
 12  len[tot]:=c;
 13  head[a]:=tot;
 14 end;
 15 
 16 procedure dfs(u:longint);
 17 var e,v,de:longint;
 18     t:int64;
 19 begin
 20  flag[u]:=1;
 21  e:=head[u];
 22  de:=0;
 23  while e<>0 do
 24  begin
 25   v:=vet[e];
 26   if flag[v]=0 then
 27   begin
 28    dfs(v); inc(de);
 29    t:=f[v,3]+len[e];
 30    if (t>f[u,1])or(f[u,1]=0) then
 31    begin
 32     f[u,2]:=f[u,1]; f[u,1]:=t;
 33    end
 34     else if (t<=f[u,1])and(t>f[u,2])or(f[u,2]=0) then f[u,2]:=t;
 35 
 36    t:=f[v,1]+len[e];
 37    if (t<f[u,3])or(f[u,3]=0) then
 38    begin
 39     f[u,4]:=f[u,3]; f[u,3]:=t;
 40    end
 41     else if (t>=f[u,3])and(t<f[u,4])or(f[u,4]=0) then f[u,4]:=t;
 42 
 43   end;
 44   e:=next[e];
 45  end;
 46 
 47 end;
 48 
 49 procedure change(u:longint);
 50 var e,v:longint;
 51     t,t1,t2,t3,t4:int64;
 52 begin
 53  e:=head[u]; flag[u]:=1;
 54  t1:=f[u,1]; t2:=f[u,2]; t3:=f[u,3]; t4:=f[u,4];
 55 
 56  ans[u]:=f[u,1];
 57  while e<>0 do
 58  begin
 59   v:=vet[e];
 60 
 61   if flag[v]=1 then begin e:=next[e]; continue; end;
 62    if f[v,3]+len[e]=t1 then t:=f[u,2]+len[e]
 63    else t:=f[u,1]+len[e];
 64    if (t<f[v,3])or(f[v,3]=0) then
 65   begin
 66    f[v,4]:=f[v,3]; f[v,3]:=t;
 67   end
 68    else if (t<f[v,4])or(f[v,4]=0) then f[v,4]:=t;
 69 
 70   if f[v,1]+len[e]=t3 then begin t:=f[u,4]+len[e];end
 71    else t:=f[u,3]+len[e];
 72 
 73 
 74   if (t>f[v,1])or(f[v,1]=0) then
 75   begin
 76    f[v,2]:=f[v,1]; f[v,1]:=t;
 77   end
 78    else if (t>f[v,2])or(f[v,2]=0) then f[v,2]:=t;
 79   change(v);
 80   e:=next[e];
 81  end;
 82 
 83 
 84 end;
 85 
 86 begin
 87  assign(input,'travel.in'); reset(input);
 88  assign(output,'travel.out'); rewrite(output);
 89  oo:=1<<63;
 90  readln(n);      //f[u,1]zuida f[u,2]cida
 91                  //f[u,3]zuixiao f[u,4]cixiao
 92  for i:=1 to n-1 do
 93  begin
 94   readln(x,y,z);
 95   add(x,y,z);
 96   add(y,x,z);
 97  end;
 98 
 99  dfs(1);
100  fillchar(flag,sizeof(flag),0);
101  change(1);
102  for i:=1 to n do writeln(ans[i]);
103  close(input);
104  close(output);
105 end.

 

  

   

 

posted on 2016-10-24 16:33  myx12345  阅读(926)  评论(0编辑  收藏  举报

导航