• bzoj2286


    很明显,20%=mincut 40%=每次暴力树形dp
    那么正解是什么呢?不难发现∑ki<=500000,也就是每次询问的复杂度都要跟k有关
    从树形dp工作的角度来看,确实有很多点我们根本就没必要访问,我们设每次要割断的岛屿为关键点
    这里引入了一个新的东西叫做虚树,简单来说就是把树上没用的点去掉收缩成一棵树
    具体来说,如果一个点的子树中至多只有一棵子树包含关键点,那么这个点就可以删掉
    也就是说只有关键点和他们的lca会被保留下来就行了,证明总点数<=2*k-1
    那么怎么构建虚树?我们先按dfs序排序,然后按这个顺序不断加点维护虚树上最新的路径
    感觉建树的方法只可意会不可言传,具体见代码吧……

      1 type node=record
      2        len,po,next:longint;
      3      end;
      4 
      5 var e:array[0..500010] of node;
      6     anc:array[0..250010,0..20] of longint;
      7     b,d,p,c,fa,st,a:array[0..250010] of longint;
      8     f:array[0..250010] of int64;
      9     v:array[0..250010] of boolean;
     10     w,s,m,h,t,n,len,i,x,y,z:longint;
     11 
     12 function min(a,b:longint):longint;
     13   begin
     14     if a>b then exit(b) else exit(a);
     15   end;
     16 
     17 procedure swap(var a,b:longint);
     18   var c:longint;
     19   begin
     20     c:=a;
     21     a:=b;
     22     b:=c;
     23   end;
     24 
     25 procedure sort(l,r: longint);
     26   var i,j,x:longint;
     27   begin
     28     i:=l;
     29     j:=r;
     30     x:=b[a[(l+r) shr 1]];
     31     repeat
     32       while b[a[i]]<x do inc(i);
     33       while x<b[a[j]] do dec(j);
     34       if not(i>j) then
     35       begin
     36         swap(a[i],a[j]);
     37         inc(i);
     38         j:=j-1;
     39       end;
     40     until i>j;
     41     if l<j then sort(l,j);
     42     if i<r then sort(i,r);
     43   end;
     44 
     45 procedure add(x,y,z:longint);
     46   begin
     47     inc(len);
     48     e[len].po:=y;
     49     e[len].len:=z;
     50     e[len].next:=p[x];
     51     p[x]:=len;
     52   end;
     53 
     54 procedure dfs(x:longint);
     55   var i,y:longint;
     56   begin
     57     inc(t);
     58     b[x]:=t;  //dfs序
     59     for i:=1 to h do
     60     begin
     61       y:=anc[x,i-1];
     62       if y<>0 then anc[x,i]:=anc[y,i-1]
     63       else break;
     64     end;
     65     i:=p[x];
     66     while i<>0 do
     67     begin
     68       y:=e[i].po;
     69       if fa[x]<>y then
     70       begin
     71         fa[y]:=x;
     72         anc[y,0]:=x;
     73         c[y]:=min(c[x],e[i].len);  //c[]表示把这个点和根节点割开最小代价
     74         d[y]:=d[x]+1;
     75         dfs(y);
     76       end;
     77       i:=e[i].next;
     78     end;
     79   end;
     80 
     81 function lca(x,y:longint):longint;
     82   var i,p:longint;
     83   begin
     84     if d[x]<d[y] then swap(x,y);
     85     p:=trunc(ln(d[x])/ln(2));
     86     if d[x]>d[y] then
     87       for i:=p downto 0 do
     88         if d[x]-1 shl i>=d[y] then x:=anc[x,i];
     89     if x=y then exit(x);
     90     for i:=p downto 0 do
     91       if (anc[y,i]<>anc[x,i]) then
     92       begin
     93         x:=anc[x,i];
     94         y:=anc[y,i];
     95       end;
     96     exit(fa[x]);
     97   end;
     98 
     99 procedure dp(x:longint);  //dp过程很简单
    100   var i,y:longint;
    101       s:int64;
    102   begin
    103     if x=1 then f[1]:=2147483647*2147483647
    104     else f[x]:=c[x];
    105     i:=p[x];
    106     s:=0;
    107     while i<>0 do
    108     begin
    109       y:=e[i].po;
    110       dp(y);
    111       s:=s+f[y];
    112       i:=e[i].next;
    113     end;
    114     p[x]:=0;
    115     if (s<>0) then
    116       if f[x]>s then f[x]:=s;
    117   end;
    118 
    119 begin
    120   readln(n);
    121   h:=trunc(ln(n)/ln(2));
    122   for i:=1 to n-1 do
    123   begin
    124     readln(x,y,z);
    125     add(x,y,z);
    126     add(y,x,z);
    127   end;
    128   c[1]:=2147483647;
    129   dfs(1);
    130   readln(m);
    131   fillchar(p,sizeof(p),0);
    132   while m>0 do
    133   begin
    134     dec(m);
    135     read(s);
    136     for i:=1 to s do
    137       read(a[i]);
    138 
    139     sort(1,s);
    140     w:=1;
    141     for i:=2 to s do
    142       if lca(a[w],a[i])<>a[w] then  //这里一点点优化,如果存在祖先关系的关键点,肯定割祖先以上的边
    143       begin
    144         inc(w);
    145         a[w]:=a[i];
    146       end;
    147     len:=0;
    148     st[1]:=1;
    149     t:=1;
    150     for i:=1 to w do
    151     begin
    152       x:=a[i];
    153       z:=lca(x,st[t]); 
    154       while d[z]<d[st[t]] do  //这里画个图比较好理解,类似一个新路径和原来维护的路径的一个分叉
    155       begin
    156         if d[z]>=d[st[t-1]] then
    157         begin
    158           add(z,st[t],0);
    159           dec(t);
    160           if st[t]<>z then
    161           begin
    162             inc(t);
    163             st[t]:=z;
    164           end;
    165           break;
    166         end;
    167         add(st[t-1],st[t],0);  //把原来分叉的那段建出来
    168         dec(t);
    169       end;
    170       if st[t]<>x then
    171       begin
    172         inc(t);
    173         st[t]:=x;
    174       end;
    175     end;
    176     while t>1 do   //把维护的路径建出来
    177     begin
    178       add(st[t-1],st[t],0);
    179       dec(t);
    180     end;
    181     dp(1);
    182     writeln(f[1]);
    183   end;
    184 end.
    View Code
  • 相关阅读:
    CFA 财务分析与估值 3.贴现现金流估值模型
    量化 量化回测框架
    Python Python语法
    Python __name__ == '__main__' 到底是什么意思
    量化 多因子策略2 : 单因子有效性,多因子相关性,多因子合成
    去重
    docker搭建redis主从复制
    suse简单使用
    grafana
    mongo学习笔记
  • 原文地址:https://www.cnblogs.com/phile/p/4472966.html
Copyright © 2020-2023  润新知