• bzoj 3611 [Heoi2014]大工程(虚树+DP)


    3611: [Heoi2014]大工程

    Time Limit: 60 Sec  Memory Limit: 512 MB
    Submit: 408  Solved: 190
    [Submit][Status][Discuss]

    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 

    Source

    【思路】

           虚树+树上DP

           对每次询问构造虚树,在虚树上进行DP。

           ans1和ans2即树上的最长/短链问题,利用前缀和思想可以求解。

       设sum[x] = ∑(sum[y] + w * size[y]); 则有

        ans += ∑((sum[y] + w * size[y]) * (size[x] - size[y]));

       其中size[x]表示以x为根的子树包含的询问点数目,w为x->y的边长。

       好大的工程=-=

    【代码】

      1 #include<cstdio>
      2 #include<vector>
      3 #include<cstring>
      4 #include<iostream>
      5 #include<algorithm>
      6 using namespace std;
      7 
      8 const int N = 1000000+10;
      9 const int INF = 1e9+1e9;
     10 const int D = 22;
     11 
     12 typedef long long LL;
     13 vector<int> G[N],g[N];
     14 int d[N],dfn[N];
     15 int n,q,dfsc;
     16 
     17 void adde(int u,int v) {
     18     if(u!=v) G[u].push_back(v); else return;
     19 }
     20 bool cmp(const int& lhs,const int& rhs) { 
     21     return dfn[lhs]<dfn[rhs];
     22 }
     23 ////////////////////////////////////////////////////lca which cuts down about 5000ms
     24 int siz[N],top[N],son[N],fa[N];
     25 void dfs1(int u) {
     26     siz[u]=1,son[0]=0; dfn[u]=++dfsc;
     27     for(int i=0;i<g[u].size();i++) {
     28         int v=g[u][i];
     29         if(v!=fa[u]) {
     30             fa[v]=u; d[v]=d[u]+1;
     31             dfs1(v);
     32             siz[u]+=siz[v];
     33             if(siz[v]>siz[son[u]]) son[u]=v;
     34         }
     35     }
     36 }
     37 void dfs2(int u,int tp) {
     38     top[u]=tp;
     39     if(son[u]) dfs2(son[u],tp);
     40     for(int i=0;i<g[u].size();i++) {
     41         int v=g[u][i];
     42         if(v!=son[u] && v!=fa[u]) dfs2(v,v);
     43     }
     44 }
     45 int LCA(int u,int v) {
     46     while(top[u]!=top[v])
     47         if(d[top[u]]>=d[top[v]]) u=fa[top[u]];
     48         else v=fa[top[v]];
     49     return d[u]<d[v]? u:v;
     50 }
     51 ////////////////////////////////////////////////
     52 LL sum[N],ans; 
     53 int ans1,ans2,mi[N],mx[N],sz[N]; bool ifq[N];
     54 int dp(int u) {
     55     sum[u]=0; sz[u]=ifq[u];
     56     mi[u]=ifq[u]? 0:INF;
     57     mx[u]=ifq[u]? 0:-INF; 
     58     for(int i=0;i<G[u].size();i++) {
     59         int v=G[u][i],w=d[v]-d[u];
     60         dp(v);
     61         sz[u]+=sz[v];
     62         sum[u]+=sum[v]+sz[v]*w;
     63         ans1=min(ans1,mi[u]+mi[v]+w);    
     64         ans2=max(ans2,mx[u]+mx[v]+w);
     65         mi[u]=min(mi[u],mi[v]+w);
     66         mx[u]=max(mx[u],mx[v]+w);
     67     }
     68     for(int i=0;i<G[u].size();i++) {
     69         int v=G[u][i],w=d[v]-d[u];
     70         ans+=(sum[v]+sz[v]*w)*(sz[u]-sz[v]);
     71     }
     72     ifq[u]=0; G[u].clear();            //clear
     73 }
     74 void read(int& x) {
     75     char c=getchar();while(!isdigit(c))c=getchar();
     76     x=0;while(isdigit(c))x=x*10+c-'0' , c=getchar();
     77 }
     78 void solve() {
     79     int tot=0,top=0,k;
     80     static int st[N],h[N];
     81     read(k);
     82     for(int i=1;i<=k;i++) read(h[i]),ifq[h[i]]=1;
     83     sort(h+1,h+k+1,cmp);
     84     st[++top]=1;
     85     for(int i=1;i<=k;i++) {
     86         int p=h[i],lca=LCA(p,st[top]);
     87         for(;;) {
     88             if(d[lca]>=d[st[top-1]]) {
     89                 adde(lca,st[top]);
     90                 top--;
     91                 if(st[top]!=lca) st[++top]=lca;
     92                 break;
     93             }
     94             adde(st[top-1],st[top]); top--;
     95         }
     96         if(st[top]!=p) st[++top]=p;
     97     }
     98     while(--top) adde(st[top],st[top+1]);
     99     ans=ans2=0 , ans1=INF;
    100     dp(1);
    101     printf("%lld %d %d
    ",ans,ans1,ans2);
    102 }
    103 int main() {
    104     read(n);
    105     int u,v;
    106     for(int i=1;i<n;i++) {
    107         read(u),read(v);
    108         g[u].push_back(v) , g[v].push_back(u);
    109     }
    110     d[1]=1; dfs1(1); dfs2(1,1);
    111     read(q);
    112     while(q--) solve();
    113     return 0;
    114 }
  • 相关阅读:
    二分图匹配初步
    动态规划初步
    一些排日程的经典方法
    petri网初步
    笔记:美国院士教你写论文
    Ubuntu18.04彻底删除MySQL数据库
    ubuntu18.04 安装 wps2019
    ubuntu18.04 阿里镜像源
    Ubuntu 18.04 使用标准Ubuntu 仓库进行自动化安装NVIDIA驱动
    linux maven环境变量配置
  • 原文地址:https://www.cnblogs.com/lidaxin/p/5115660.html
Copyright © 2020-2023  润新知