[BZOJ2286] [Sdoi2011]消耗战

来源:互联网 发布:网络博客大全评级 编辑:程序博客网 时间:2024/05/20 02:51

传送门

http://www.lydsy.com/JudgeOnline/problem.php?id=2286

题目大意

给定一棵树,树上有边权,切断一条边消耗边权大小的能量
每次给定一些关键点,使这些关键点都不能与1联通,询问最小代价

题解

树形DP
dp[i]:使i
dp[i]=min{dp[son[i]],w[i,son[i]]}son[i]/w[i,son[i]]son[i]
复杂度O(NM)超时
我们发现其实不用每次都对整棵树做一遍DP,每次只留下关键点和汇集关键点的点(lca)即可
(下面的父子关系是省略无关点后的新树)
dp[i]=min{dp[son[i]],w[i,son[i]]}son[i]/w[i,son[i]]son[i]
其中w[i,son[i]]是原树中两点见的最小边权
可以用ST表预处理出来做到每次O(logN)
(这一种抛去无关点建立的新树通常叫做虚树)
如何建立,看下面一段

接下来所说的”树”均指虚树,原来那棵树叫做”原树”.
构建过程如下:
按照原树的dfs序号(记为dfn)递增顺序遍历选择的节点. 每次遍历节点都把这个节点插到树上.
首先虚树一定要有一个根. 随便扯一个不会成为询问点的点作根.
维护一个栈,它表示在我们已经(用之前的那些点)构建完毕的虚树上,以最后一个插入的点为端点的DFS链.
设最后插入的点为p(就是栈顶的点),当前遍历到的点为x.我们想把x插入到我们已经构建的树上去.
求出lca(p,x),记为lca.有两种情况:
  1.p和x分立在lca的两棵子树下.
  2.lca是p.
  (为什么lca不能是x?
   因为如果lca是x,说明dfn(lca)=dfn(x)

const    maxn=250000;var    w:array[0..3*maxn,1..3]of longint;    dp:array[0..maxn]of int64;    pos,dep,t,s,v,p:array[0..maxn]of longint;    st:array[0..maxn,0..20]of longint;    dis:array[0..maxn,0..20]of int64;    i,j,k:longint;    n,m,len,a,b,c,tt:longint;function min(a,b:int64):int64;begin if a>b then exit(b) else exit(a); end;procedure init(a,b,c:longint);begin    w[len,1]:=b; w[len,2]:=c;    if w[a,3]=0 then w[a,3]:=len else w[w[a,1],3]:=len;    w[a,1]:=len; inc(len);end;procedure sort(l,r:longint);var i,j,a,b:longint;begin    i:=l;j:=r;a:=pos[s[(l+r)div 2]];    repeat        while (pos[s[i]]<a) do inc(i);        while (pos[s[j]]>a) do dec(j);        if not(i>j) then begin b:=s[i]; s[i]:=s[j]; s[j]:=b; inc(i); dec(j); end;    until i>j;    if l<j then sort(l,j);    if i<r then sort(i,r);end;procedure dfs(a:longint);var tt:longint;begin    tt:=w[a,3]; inc(len); pos[a]:=len;    while tt<>0 do        begin            if (w[tt,1]<>st[a,0])            then                begin                    dep[w[tt,1]]:=dep[a]+1;                    st[w[tt,1],0]:=a;                    dis[w[tt,1],0]:=w[tt,2];                    dfs(w[tt,1]);                end;            tt:=w[tt,3];        end;end;procedure prepare;var i:longint;begin    len:=0; dep[1]:=1; dfs(1);    for i:=1 to 20 do        for j:=1 to n do            st[j,i]:=st[st[j,i-1],i-1];    for i:=1 to 20 do        for j:=1 to n do            dis[j,i]:=min(dis[j,i-1],dis[st[j,i-1],i-1]);end;function lca(a,b:longint):longint;var i:longint;begin    if dep[a]<dep[b] then begin i:=a; a:=b; b:=i; end;    for i:=20 downto 0 do        if dep[st[a,i]]>=dep[b]        then a:=st[a,i];    if a=b then exit(a);    for i:=20 downto 0 do        if st[a,i]<>st[b,i]        then begin a:=st[a,i]; b:=st[b,i]; end;    exit(st[a,0]);end;function distance(a,b:longint):int64;var ans:int64; i:longint;begin    if dep[a]<dep[b] then begin i:=a; a:=b; b:=i; end;    ans:=maxlongint;    for i:=20 downto 0 do        if dep[st[a,i]]>=dep[b]        then begin ans:=min(ans,dis[a,i]); a:=st[a,i]; end;    exit(ans);end;begin    readln(n); len:=n+1;    for i:=1 to n-1 do        begin            readln(a,b,c);            init(a,b,c); init(b,a,c);        end;    prepare;    readln(m);    for i:=1 to m do        begin            read(a);            for j:=1 to a do                begin read(s[j]); v[s[j]]:=1; end;            sort(1,a);            t[1]:=1; t[0]:=1; p[0]:=1; p[1]:=1; len:=n+1;            for j:=1 to a do                begin                    tt:=lca(t[t[0]],s[j]);                    if tt=t[t[0]]                    then begin inc(t[0]); t[t[0]]:=s[j]; inc(p[0]); p[p[0]]:=s[j]; end                    else                        begin                            while dep[t[t[0]-1]]>dep[tt] do                                begin                                    if v[t[t[0]]]=1                                    then inc(dp[t[t[0]-1]],distance(t[t[0]],t[t[0]-1]))                                    else inc(dp[t[t[0]-1]],min(distance(t[t[0]],t[t[0]-1]),dp[t[t[0]]]));                                    dp[t[t[0]]]:=0; dec(t[0]);                                end;                            if v[t[t[0]]]=1                            then inc(dp[tt],distance(tt,t[t[0]]))                            else inc(dp[tt],min(distance(tt,t[t[0]]),dp[t[t[0]]]));                            dp[t[t[0]]]:=0; dec(t[0]);                            if t[t[0]]<>tt then begin inc(t[0]); t[t[0]]:=tt; inc(p[0]); p[p[0]]:=s[j]; end;                            inc(t[0]); t[t[0]]:=s[j]; inc(p[0]); p[p[0]]:=s[j];                        end;                end;            while t[0]>1 do                begin                    if v[t[t[0]]]=1                    then inc(dp[t[t[0]-1]],distance(t[t[0]],t[t[0]-1]))                    else begin inc(dp[t[t[0]-1]],min(distance(t[t[0]],t[t[0]-1]),dp[t[t[0]]])); dp[t[t[0]]]:=0; end;                    dec(t[0]);                  end;            writeln(dp[1]);             for j:=1 to p[0] do                dp[p[j]]:=0;            for j:=1 to a do                v[s[j]]:=0;        end;end.
0 0