bzoj 2286
第一道"虚树"题目(好吧,我也不知道这是不是虚树,但和虚树的思想肯定是一样的,都是简化树结构)
这一类算法核心思想都是简化树结构,只取我们必须的节点和一些信息,然后在简化后的树结构上工作。
首先,如果这道题只有一次询问,那么很容易想到树形DP的解法,但这道题又多组询问,并且限制了所有询问的关键点个数,这意味着我们必须设计出一种算法,她回答一组询问的复杂度只和关键点个数相关(O(k)或O(klogk)都是可接受的),而和原图无关(最多加个logn)。
然后就有了虚树,我们可以构建一个新的树,这棵树上有所有关键点,以及相邻dfs序上相邻的两个关键点的lca,我们发现,这样的图包括了所有关键点的lca以及所有关键点,然后改一下DP就可以在这棵树上快速的搞了(因为节点个数是O(2*k),所以这样DP的复杂度就从O(n)变成了O(k))。
DP:
dp[i]表示将i及其子树中所有关键点与跟节点断开所需的最小代价(可以砍他们上面的边)
构简化图:
对于一个询问,我们先将其关键点按照DFS序排序。然后维护一个栈保存当前走了的关键点或关键点之间的LCA,当我们要插入一个新的关键节点时,我们根据当前节点与当前栈顶节点LCA的深度与栈顶元素的深度来判断是否需要弹出节点,一直弹出,直到深度大于等于栈顶元素(注意,这个LCA是最初的栈顶与新的关键节点的LCA)
1 /************************************************************** 2 Problem: 2286 3 User: idy002 4 Language: C++ 5 Result: Accepted 6 Time:6700 ms 7 Memory:32060 kb 8 ****************************************************************/ 9 10 #include <cstdio> 11 #include <vector> 12 #include <algorithm> 13 #define min(a,b) ((a)<(b)?(a):(b)) 14 #define oo 0x3f3f3f3f 15 #define N 250010 16 #define P 17 17 using namespace std; 18 19 typedef long long dnt; 20 21 int n, m; 22 int head[N], dest[N+N], wght[N+N], next[N+N], ntot; 23 int dfn[N], dep[N], bst[N], anc[N][P+1], idc; 24 int qcnt, aa[N], stk[N], top; 25 dnt dp[N]; 26 27 void adde( int u, int v, int w ) { 28 ntot++; 29 wght[ntot] = w; 30 dest[ntot] = v; 31 next[ntot] = head[u]; 32 head[u] = ntot; 33 } 34 void dfs( int u ) { 35 dfn[u] = ++idc; 36 for( int p=1; p<=P; p++ ) 37 anc[u][p] = anc[anc[u][p-1]][p-1]; 38 for( int t=head[u]; t; t=next[t] ) { 39 int v=dest[t], w=wght[t]; 40 if( v==anc[u][0] ) continue; 41 anc[v][0] = u; 42 bst[v] = min( bst[u], w ); 43 dep[v] = dep[u]+1; 44 dfs(v); 45 } 46 } 47 bool cmp( int u, int v ) { 48 return dfn[u]<dfn[v]; 49 } 50 int lca( int u, int v ) { 51 if( dep[u]<dep[v] ) swap(u,v); 52 int t=dep[u]-dep[v]; 53 for( int p=0; t; t>>=1,p++ ) 54 if( t&1 ) u=anc[u][p]; 55 if( u==v ) return u; 56 for( int p=P; p>=0 && anc[u][0]!=anc[v][0]; p-- ) 57 if( anc[u][p]!=anc[v][p] ) 58 u=anc[u][p], v=anc[v][p]; 59 return anc[u][0]; 60 } 61 void sov() { 62 scanf( "%d", &qcnt ); 63 for( int i=1; i<=qcnt; i++ ) 64 scanf( "%d", aa+i ); 65 sort( aa+1, aa+1+qcnt, cmp ); 66 67 stk[top=1] = 1; 68 dp[1] = 0; 69 for( int i=1; i<=qcnt; i++ ) { 70 int ca=lca(aa[i],stk[top]); 71 while( dep[stk[top]]>dep[ca] ) { 72 int fa, u; 73 u = stk[top]; 74 top--; 75 if( dep[stk[top]]<=dep[ca] ) { 76 if( dep[stk[top]]<dep[ca] ) { 77 stk[++top] = ca; 78 dp[ca] = 0; 79 } 80 fa = stk[top]; 81 82 dp[u] = min( dp[u], bst[u] ); 83 dp[fa] += dp[u]; 84 break; 85 } 86 fa = stk[top]; 87 88 dp[u] = min( dp[u], bst[u] ); 89 dp[fa] += dp[u]; 90 } 91 int u=aa[i]; 92 stk[++top] = u; 93 94 dp[u] = bst[u]; 95 } 96 while( top ) { 97 if( top-1 ) { 98 int fa=stk[top-1], u=stk[top]; 99 100 dp[u] = min( dp[u], bst[u] ); 101 dp[fa] += dp[u]; 102 } 103 top--; 104 } 105 printf( "%lld\n", dp[1] ); 106 } 107 int main() { 108 scanf( "%d", &n ); 109 for( int i=1,u,v,w; i<n; i++ ) { 110 scanf( "%d%d%d", &u, &v, &w ); 111 adde( u, v, w ); 112 adde( v, u, w ); 113 } 114 anc[1][0] = 1; 115 dep[1] = 1; 116 bst[1] = oo; 117 dfs(1); 118 scanf( "%d", &m ); 119 for( int i=1; i<=m; i++ ) 120 sov(); 121 }