• [虚树][树形dp] Bzoj P3611 大工程


    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 

    题解

    • 也像上一题消耗战一样,构造出虚树上树形dp就好了

    代码

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<cmath>
     7 #define N 1000010
     8 #define ll long long
     9 #define inf 0x3fffffff
    10 using namespace std;
    11 int cnt,n,m,k,head[N],last[N],dep[N],fa[N][20],size[N],mx[N],mn[N],ans2,ans3,tim,dfn[N],logn,a[N],flag[N],st[N];
    12 ll sum[N],ans1;
    13 struct edge{int to,from;}e[N*2];
    14 void insert1(int u,int v)
    15 {
    16     e[++cnt].to=v,e[cnt].from=head[u],head[u]=cnt;
    17     e[++cnt].to=u,e[cnt].from=head[v],head[v]=cnt;
    18 }
    19 void insert2(int u,int v)
    20 {
    21     if (u==v) return;
    22     e[++cnt].to=v,e[cnt].from=last[u],last[u]=cnt;
    23 }
    24 void dfs(int x)
    25 {
    26     dfn[x]=++tim;
    27     for (int i=1;i<=logn;i++) fa[x][i]=fa[fa[x][i-1]][i-1];
    28     dep[x]=dep[fa[x][0]]+1;
    29     for (int i=head[x];i;i=e[i].from) if (e[i].to!=fa[x][0]) fa[e[i].to][0]=x,dfs(e[i].to);
    30 }
    31 int getlca(int x,int y)
    32 {
    33     if (dep[x]<dep[y]) swap(x,y);
    34     for (int i=logn;i>=0;i--) if (dep[fa[x][i]]>=dep[y]) x=fa[x][i];
    35     if (x==y) return x;
    36     for (int i=logn;i>=0;i--) if (fa[x][0]!=fa[y][0]) x=fa[x][0],y=fa[y][0];
    37     return fa[x][0];
    38 }
    39 bool cmp(int a,int b) { return dfn[a]<dfn[b]; }
    40 void dp(int x)
    41 {
    42     int mx1=0,mx2=0,mn1=inf,mn2=inf;size[x]=0;sum[x]=0;
    43     if (flag[x]) size[x]++,sum[x]=dep[x],mn1=0;
    44     for (int i=last[x];i;i=e[i].from)
    45     {
    46         dp(e[i].to);
    47         size[x]+=size[e[i].to];sum[x]+=sum[e[i].to];
    48         if (mx[e[i].to]+dep[e[i].to]-dep[x]>mx1) mx2=mx1,mx1=mx[e[i].to]+dep[e[i].to]-dep[x];
    49         else if (mx[e[i].to]+dep[e[i].to]-dep[x]>mx2) mx2=mx[e[i].to]+dep[e[i].to]-dep[x];
    50         if (mn[e[i].to]+dep[e[i].to]-dep[x]<mn1) mn2=mn1,mn1=mn[e[i].to]+dep[e[i].to]-dep[x];
    51         else if (mn[e[i].to]+dep[e[i].to]-dep[x]<mn2) mn2=mn[e[i].to]+dep[e[i].to]-dep[x];
    52     }
    53     for (int i=last[x];i;i=e[i].from) ans1+=(ll)(size[x]-size[e[i].to])*(sum[e[i].to]-(ll)size[e[i].to]*dep[x]);
    54     ans2=min(ans2,mn1+mn2);
    55     if (flag[x]||!flag[x]&&mx2) ans3=max(ans3,mx1+mx2);
    56     mx[x]=mx1;mn[x]=mn1,last[x]=0;
    57 }
    58 void solve()
    59 {
    60     cnt=0,scanf("%d",&k);
    61     for (int i=1;i<=k;i++) scanf("%d",&a[i]),flag[a[i]]=1;
    62     sort(a+1,a+k+1,cmp);
    63     int top=1; st[1]=1;
    64     for (int i=1;i<=k;i++)
    65     {
    66         int now=a[i],f=getlca(now,st[top]);
    67         while (1)
    68         {
    69             if (dep[f]>=dep[st[top-1]])
    70             {
    71                 insert2(f,st[top]),top--;
    72                 if (st[top]!=f) st[++top]=f;
    73                 break;
    74             }
    75             insert2(st[top-1],st[top]),top--;
    76         }
    77         if (st[top]!=now) st[++top]=now;
    78     }
    79     while (top>1) insert2(st[top-1],st[top]),top--;
    80     ans1=ans3=0;ans2=inf,dp(1);
    81     for (int i=1;i<=k;i++) flag[a[i]]=0;
    82     printf("%lld %d %d
    ",ans1,ans2,ans3);
    83 }
    84 int main()
    85 {
    86     freopen("data.in","r",stdin);
    87     scanf("%d",&n);
    88     for (int i=1,x,y;i<n;i++) scanf("%d%d",&x,&y),insert1(x,y);
    89     logn=log(n)/log(2),dfs(1),scanf("%d",&m);
    90     for (int i=1;i<=m;i++) solve();
    91 }
  • 相关阅读:
    什么是内卷?
    iphone与PC端如何传BUG截图
    java应用服务占用cpu过高,如何优化
    性能测试常见问题FAQ
    性能测试工程师能力进阶三部曲
    jmeter分布式压测试部署
    了解token及分类
    常见端口号及其服务
    2714
    python
  • 原文地址:https://www.cnblogs.com/Comfortable/p/11136797.html
Copyright © 2020-2023  润新知