zoukankan      html  css  js  c++  java
  • bzoj3611: [Heoi2014]大工程

    Description

    国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。 
    我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。 
    在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径。
     现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道。
    现在对于每个计划,我们想知道:
     1.这些新通道的代价和
     2.这些新通道中代价最小的是多少 
    3.这些新通道中代价最大的是多少

    Input

    第一行 n 表示点数。

     接下来 n-1 行,每行两个数 a,b 表示 a 和 b 之间有一条边。
    点从 1 开始标号。 接下来一行 q 表示计划数。
    对每个计划有 2 行,第一行 k 表示这个计划选中了几个点。
     第二行用空格隔开的 k 个互不相同的数表示选了哪 k 个点。

    Output

    输出 q 行,每行三个数分别表示代价和,最小代价,最大代价。 

     

    Sample Input

    10
    2 1
    3 2
    4 1
    5 2
    6 4
    7 5
    8 6
    9 7
    10 9
    5
    2
    5 4
    2
    10 4
    2
    5 2
    2
    6 1
    2
    6 1

    Sample Output

    3 3 3
    6 6 6
    1 1 1
    2 2 2
    2 2 2

    HINT

    n<=1000000 

    q<=50000并且保证所有k之和<=2*n
     
    Orz CYY
    CYY讲了一个叫虚树的东西,然后这道题就变的很水了
    题解:
    先说下虚树是什么东西
    虚树就是只包括了给定的关键点和这些点的lca所构成的树,树上的父子兄弟关系保持不变
    举个例子:
    原树是这样的
    假如选了1、5、8、10号节点,那么虚树为
    如何构建虚树
    先dfs一遍原树,得到dfs序和其他你可能要用的东西
    然后将读入的点按dfs序排遍序
    用一个栈保留前面所有点所构成的虚树的最右边的那条链
    现在加入一个新的点,先求一下当前点和栈顶的点的lca
    如果lca的dfs序小于栈顶的点的dfs序,就把那个点弹出来
    此时如果栈顶的点dfs序还是大于lca的dfs序,就将当前栈顶的点和前面刚弹出的点连条边,然后重复此过程
    否则就将lca和刚弹出的点连条边,如果栈顶的点和lca不同,则将lca入栈
    最后将这个新的点入栈(感觉好乱,自己看图和代码yy下)
    建立虚树可以把大多数一些不需要去掉,从而每次询问的复杂度为O(m)(m为给定点数)
    所以虚树的题有个很明显的特征,就是Σm会小于一个和n同阶的数
    这题就在虚树上进行dp
    设f[u]表示所有路径在以u为根的子树的总长度
    g[0][u]表示从u出发,到子树中最近的一个给定点的距离,g[1][u]表示最远的
    转移自己yy下,比较简单,注意一些细节
    code:
     1 #include<cstdio> 
     2 #include<iostream> 
     3 #include<cmath> 
     4 #include<cstring> 
     5 #include<algorithm> 
     6 #define maxn 1000005 
     7 #define inf 1061109567 
     8 using namespace std; 
     9 typedef long long int64; 
    10 char ch; 
    11 bool ok; 
    12 void read(int &x){ 
    13     for (ok=0,ch=getchar();!isdigit(ch);ch=getchar()) if (ch=='-') ok=1; 
    14     for (x=0;isdigit(ch);x=x*10+ch-'0',ch=getchar()); 
    15     if (ok) x=-x; 
    16 } 
    17 int n,q,a,b,k; 
    18 int idx,fa[maxn][21],dfn[maxn],dis[maxn],cnt,top,list[maxn],stack[maxn],bo[maxn]; 
    19 int ans1,ans2,siz[maxn],g[2][maxn]; 
    20 int64 f[maxn]; 
    21 bool cmp(int a,int b){return dfn[a]<dfn[b];} 
    22 struct Graph{ 
    23     int tot,now[maxn],son[maxn<<1],pre[maxn<<1]; 
    24     void init(){tot=0,memset(now,0,sizeof(now));} 
    25     inline void put(int a,int b){pre[++tot]=now[a],now[a]=tot,son[tot]=b;} 
    26     inline void dfs1(int u){ 
    27         dfn[u]=++idx; 
    28         for (int i=0;fa[u][i];i++) fa[u][i+1]=fa[fa[u][i]][i]; 
    29         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]) 
    30             if (v!=fa[u][0]) fa[v][0]=u,dis[v]=dis[u]+1,dfs1(v); 
    31     } 
    32     inline void dfs2(int u){ 
    33         siz[u]=bo[u]; 
    34         f[u]=0,g[0][u]=inf,g[1][u]=0; 
    35         for (int p=now[u],v=son[p];p;p=pre[p],v=son[p]){ 
    36             dfs2(v),siz[u]+=siz[v]; 
    37             int d=dis[v]-dis[u]; 
    38             f[u]+=f[v]+1LL*siz[v]*(k-siz[v])*d; 
    39             ans1=min(ans1,g[0][u]+g[0][v]+d),ans2=max(ans2,g[1][u]+g[1][v]+d); 
    40             g[0][u]=min(g[0][u],g[0][v]+d); 
    41             g[1][u]=max(g[1][u],g[1][v]+d); 
    42         } 
    43         if (bo[u]) ans1=min(ans1,g[0][u]),ans2=max(ans2,g[1][u]),g[0][u]=0; 
    44         now[u]=0; 
    45     } 
    46 }G1,G2; 
    47 void swim(int &u,int h){for (int i=20;h;i--) if (h>=(1<<i)) h-=(1<<i),u=fa[u][i];} 
    48 int calc_lca(int u,int v){ 
    49     if (dis[u]<dis[v]) swap(u,v); 
    50     swim(u,dis[u]-dis[v]); 
    51     if (u==v) return u; 
    52     for (int i=20;i>=0;i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; 
    53     return fa[u][0]; 
    54 } 
    55 int main(){ 
    56     read(n); 
    57     for (int i=1;i<n;i++) read(a),read(b),G1.put(a,b),G1.put(b,a); 
    58     G1.dfs1(1); 
    59     for (read(q);q;q--){ 
    60         read(k),cnt=top=0; 
    61         for (int i=1;i<=k;i++) read(list[i]),bo[list[i]]=1; 
    62         sort(list+1,list+k+1,cmp); 
    63         for (int i=1;i<=k;i++){ 
    64             if (!top){stack[++top]=list[i];continue;} 
    65             int lca=calc_lca(stack[top],list[i]); 
    66             while (dfn[lca]<dfn[stack[top]]){ 
    67                 if (dfn[lca]>=dfn[stack[top-1]]){ 
    68                     G2.put(lca,stack[top]); 
    69                     if (stack[--top]!=lca) stack[++top]=lca; 
    70                     break; 
    71                 } 
    72                 G2.put(stack[top-1],stack[top]),top--; 
    73             } 
    74             stack[++top]=list[i]; 
    75         } 
    76         while (top>1) G2.put(stack[top-1],stack[top]),top--; 
    77         ans1=inf,ans2=0; 
    78         G2.dfs2(stack[1]); 
    79         printf("%lld %d %d
    ",f[stack[1]],ans1,ans2); 
    80         for (int i=1;i<=k;i++) bo[list[i]]=0; 
    81         G2.tot=0; 
    82     } 
    83     return 0; 
    84 } 
  • 相关阅读:
    Ural 1099 Work Scheduling (一般图的最大匹配:带花树算法)
    HDU 4687 Boke and Tsukkomi (2013.8.20 多校9 1002)(暴力+带花树算法)
    2013 Multi-University Training Contest 9 小结(2013.8.20)
    TeX代码模板(持续更新中)
    POJ 3177 Redundant Paths
    POJ 1904 King's Quest
    hdu 4685 Prince and Princess (2013.8.15 多校8---1010)
    2-SAT模板(修改自LRJ的模板)
    HDU 3622 Bomb Game
    Ubuntu 压缩命令
  • 原文地址:https://www.cnblogs.com/chenyushuo/p/5069169.html
Copyright © 2011-2022 走看看