• 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
    ", 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 }
    View Code
  • 相关阅读:
    .htaccess
    windows快速搭建wamp环境,多站点域名访问
    require与include的区别
    PHP常用操作的字符串函数
    高效做事的习惯
    成功?!
    面向对象程序设计
    失落 绝望
    jquery学习收获
    XML操作类
  • 原文地址:https://www.cnblogs.com/idy002/p/4393938.html
Copyright © 2020-2023  润新知