zoukankan      html  css  js  c++  java
  • 【BZOJ2286】消耗战(虚树,DFS序,树形DP)

    题意:一棵N个点的树上有若干个关键点,每条边有一个边权,现在要将这些关键点到1的路径全部切断,切断一条边的代价就是边权。

    共有M组询问,每组询问有k[i]个关键点,对于每组询问求出完成任务的最小代价。

    对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1

    思路:第一题虚树,需要详细地记录一下。

    对于此题,朴素的树形DP很好理解:

    dp[u]为将u子树中的关键点全部切断的最小代价

    dp[u]=min(cut[u],sigma(dp[v])) 其中cut[u]为1到u中最小的边权

    但因为询问有多次且需要切断的关键点不同,会超时

    经过思考可以发现只有很少的点需要被作为关键点进行处理:当一个点是关键点,或者为某两个关键点的LCA时,这个点会被作为关键点

    显然关键点的数量是O(n)级别的

    对于每次询问重新构造一棵虚树,使用栈

    现将关键点按DFS序从小到大排序

    对于一条链上的点只需保留两个

    设新插入的点为x,栈顶的第一个点为y,第二个点为z,x与y的LCA为w:

    1.dfn[w]<dfn[z] (w,x)连边,x入栈

    2.dfn[w]=dfn[z] (y,z)连边

    3.dfn[w]>dfn[z] 将w加入栈,(w,z),(w,x)之间连边

      1 const oo=1000000000000;
      2 var head,vet,next,len,head1,vet1,next1,
      3     dep,flag,dfn,b,h,stk:array[0..500000]of longint;
      4     dp,cut:array[1..500000]of int64;
      5     f:array[1..500000,0..20]of longint;
      6     n,i,x,y,z,tot,time,que:longint;
      7 
      8 procedure add(a,b,c:longint);
      9 begin
     10  inc(tot);
     11  next[tot]:=head[a];
     12  vet[tot]:=b;
     13  len[tot]:=c;
     14  head[a]:=tot;
     15 end;
     16 
     17 function min(x,y:int64):int64;
     18 begin
     19  if x<y then exit(x);
     20  exit(y);
     21 end;
     22 
     23 procedure swap(var x,y:longint);
     24 var t:longint;
     25 begin
     26  t:=x; x:=y; y:=t;
     27 end;
     28 
     29 function lca(x,y:longint):longint;
     30 var i,d:longint;
     31 begin
     32  if dep[x]<dep[y] then swap(x,y);
     33  d:=dep[x]-dep[y];
     34  for i:=0 to 20 do
     35   if d and (1<<i)>0 then x:=f[x,i];
     36  for i:=20 downto 0 do
     37   if f[x,i]<>f[y,i] then
     38   begin
     39    x:=f[x,i]; y:=f[y,i];
     40   end;
     41  if x=y then exit(x);
     42  exit(f[x,0]);
     43 end;
     44 
     45 procedure dfs(u:longint);
     46 var e,i,v:longint;
     47 begin
     48  for i:=1 to 20 do
     49  begin
     50   if dep[u]<(1<<i) then break;
     51   f[u,i]:=f[f[u,i-1],i-1];
     52  end;
     53  inc(time); dfn[u]:=time;
     54  flag[u]:=1;
     55  e:=head[u];
     56  while e<>0 do
     57  begin
     58   v:=vet[e];
     59   if flag[v]=0 then
     60   begin
     61    f[v,0]:=u;
     62    dep[v]:=dep[u]+1;
     63    cut[v]:=min(cut[u],len[e]);
     64    dfs(v);
     65   end;
     66   e:=next[e];
     67  end;
     68 end;
     69 
     70 procedure qsort(l,r:longint);
     71 var i,j,mid:longint;
     72 begin
     73  i:=l; j:=r; mid:=b[(l+r)>>1];
     74  repeat
     75   while mid>b[i] do inc(i);
     76   while mid<b[j] do dec(j);
     77   if i<=j then
     78   begin
     79    swap(h[i],h[j]);
     80    swap(b[i],b[j]);
     81    inc(i); dec(j);
     82   end;
     83  until i>j;
     84  if l<j then qsort(l,j);
     85  if i<r then qsort(i,r);
     86 end;
     87 
     88 procedure add1(a,b:longint);
     89 begin
     90  if a=b then exit;
     91 // writeln(a,' ',b);
     92  inc(tot);
     93  next1[tot]:=head1[a];
     94  vet1[tot]:=b;
     95  head1[a]:=tot;
     96 end;
     97 
     98 procedure dfs2(u:longint);
     99 var e,v:longint;
    100     s:int64;
    101 begin
    102  e:=head1[u]; dp[u]:=cut[u];
    103  s:=0;
    104  while e<>0 do
    105  begin
    106   v:=vet1[e];
    107   dfs2(v);
    108   s:=s+dp[v];
    109   e:=next1[e];
    110  end;
    111  head1[u]:=0;
    112  if s=0 then dp[u]:=cut[u]
    113   else dp[u]:=min(s,dp[u]);
    114 end;
    115 
    116 procedure solve;
    117 var m,i,top,now,p,q:longint;
    118 begin
    119  read(m); tot:=0;
    120  for i:=1 to m do begin read(h[i]); b[i]:=dfn[h[i]]; end;
    121  qsort(1,m);
    122  q:=1;
    123  for i:=2 to m do
    124   if lca(h[q],h[i])<>h[q] then begin inc(q); h[q]:=h[i]; end;
    125  //for i:=1 to q do writeln(h[i]);
    126  stk[1]:=1; top:=1;
    127  for i:=1 to q do
    128  begin
    129   now:=h[i]; p:=lca(now,stk[top]);
    130   while true do
    131   begin
    132    if dep[p]>=dep[stk[top-1]] then
    133    begin
    134     add1(p,stk[top]); dec(top);
    135     if stk[top]<>p then begin inc(top); stk[top]:=p; end;
    136     break;
    137    end;
    138    add1(stk[top-1],stk[top]); dec(top);
    139   end;
    140   if stk[top]<>now then begin inc(top); stk[top]:=now; end;
    141  end;
    142  repeat
    143   dec(top);
    144   if top<=0 then break;
    145   add1(stk[top],stk[top+1]);
    146  until top=0;
    147  dfs2(1);
    148  writeln(dp[1]);
    149 end;
    150 
    151 begin
    152  assign(input,'bzoj2286.in'); reset(input);
    153  assign(output,'bzoj2286.out'); rewrite(output);
    154  readln(n);
    155  for i:=1 to n-1 do
    156  begin
    157   readln(x,y,z);
    158   add(x,y,z);
    159   add(y,x,z);
    160  end;
    161  readln(que);
    162  //fillchar(cut,sizeof(cut),$1f);
    163  cut[1]:=oo;
    164  dfs(1);
    165  for i:=1 to que do solve;
    166  close(input);
    167  close(output);
    168 end.
  • 相关阅读:
    Polly
    ELK
    Python基础三(选择,循环)
    Python基础二(输入与输出)
    Python关键字
    Python基础一(基本类型和运算符)
    Python发展史
    在虚拟机(vmware)上安装CentOS
    centos7联网
    Hashmap的实现
  • 原文地址:https://www.cnblogs.com/myx12345/p/6180796.html
Copyright © 2011-2022 走看看