[HEOI2014]大工程

Posted Z-Y-Y-S

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[HEOI2014]大工程相关的知识,希望对你有一定的参考价值。

题目描述

国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。

我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。

在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径。

现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道。现在对于每个计划,我们想知道: 1.这些新通道的代价和 2.这些新通道中代价最小的是多少 3.这些新通道中代价最大的是多少

输入输出格式

输入格式:

 

第一行 n 表示点数。

接下来 n-1 行,每行两个数 a,b 表示 a 和 b 之间有一条边。点从 1 开始标号。

接下来一行 q 表示计划数。对每个计划有 2 行,第一行 k 表示这个计划选中了几个点。

第二行用空格隔开的 k 个互不相同的数表示选了哪 k 个点。

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 复制
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
输出样例#1: 复制
3 3 3 
6 6 6 
1 1 1 
2 2 2 2 2 2

说明

对于第 1,2 个点: n<=10000

对于第 3,4,5 个点: n<=100000,交通网络构成一条链

对于第 6,7 个点: n<=100000

对于第 8,9,10 个点: n<=1000000

对于所有数据, q<=50000并且保证所有k之和<=2*n

看到k的和小于2*n,于是立刻想到建虚树

建出虚树后就dp

size[x]表示x的子树中关键点数

f[x]表示x子树中路径的贡献和

Min[x]表示x子树中离x距离最小的关键点的距离

Max[x]表示最大的距离

最大值和求和很简单

最大值总是要取到叶子节点,虚树中叶子节点总是关键点

答案取当前Max[x]+Max[v]+边权w,然后Max[x]=max(Max[x],Max[v]+d)

求和就考虑一条边的贡献

一条边的贡献次数显然是size[v]*(k-size[v])

所以f[x]+=f[v]+size[v]*(k-size[v])*w

求最小值的话,Min[x]初值正无穷

如果是关键点就直接取它的子树路径最小值,否则就是它的两个儿子的子树路径最小值相加

如果是关键点,更新答案后Min[x]要清0,作为接下来的端点

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 typedef long long lol;
  8 const int N=2000005;
  9 struct Node
 10 {
 11     int next,to;
 12 }edge[N],edge2[N];
 13 int inf=1e9;
 14 int dep[N],fa[N][21],dfn[N],cnt,bin[25],head[N],head2[N],num,ed[N];
 15 int size[N],vis[N],Max[N],Min[N],k,M,ans1,ans2,n,Lca,a[N],s[N],top;
 16 lol f[N];
 17 int gi()
 18 {
 19     char ch=getchar();
 20     int x=0;
 21     while (ch<0||ch>9) ch=getchar();
 22     while (ch>=0&&ch<=9) 
 23     {
 24         x=x*10+ch-0;
 25         ch=getchar();
 26     }
 27     return x;
 28 }
 29 bool cmp(int a,int b)
 30 {
 31     return dfn[a]<dfn[b];
 32 }
 33 void add(int u,int v)
 34 {
 35     num++;
 36     edge[num].next=head[u];
 37     head[u]=num;
 38     edge[num].to=v;
 39 }
 40 void add2(int u,int v)
 41 {
 42     if (u==v) return;
 43     num++;
 44     edge2[num].next=head2[u];
 45     head2[u]=num;
 46     edge2[num].to=v;
 47 }
 48 void dfs(int x,int pa)
 49 {int i;
 50     dep[x]=dep[pa]+1;
 51     dfn[x]=++cnt;
 52     for (i=1;bin[i]<=dep[x];i++)
 53     fa[x][i]=fa[fa[x][i-1]][i-1];
 54     for (i=head[x];i;i=edge[i].next)
 55     {
 56         int v=edge[i].to;
 57         if (v==pa) continue;
 58         fa[v][0]=x;
 59         dfs(v,x);
 60     }
 61     ed[x]=cnt;
 62 }
 63 int lca(int x,int y)
 64 {int as,i;
 65     if (dep[x]<dep[y]) swap(x,y);
 66     for (i=20;i>=0;i--)
 67     if (bin[i]<=dep[x]-dep[y])
 68     x=fa[x][i];
 69     if (x==y) return x;
 70     for (i=20;i>=0;i--)
 71     {
 72         if (fa[x][i]!=fa[y][i])
 73         {
 74             x=fa[x][i];y=fa[y][i];
 75         }
 76     }
 77     return fa[x][0];
 78 }
 79 
 80 void dp(int x)
 81 {int i;
 82     size[x]=vis[x];
 83     Max[x]=0;Min[x]=inf;f[x]=0;
 84     for (i=head2[x];i;i=edge2[i].next)
 85     {
 86         int v=edge2[i].to,d=dep[v]-dep[x];
 87         dp(v);
 88         size[x]+=size[v];
 89         f[x]+=f[v]+1ll*size[v]*(k-size[v])*d;
 90         ans1=min(ans1,Min[x]+Min[v]+d);Min[x]=min(Min[x],Min[v]+d);
 91         ans2=max(ans2,Max[x]+Max[v]+d);Max[x]=max(Max[x],Max[v]+d);
 92     }
 93     if (vis[x]) ans1=min(ans1,Min[x]),ans2=max(ans2,Max[x]),Min[x]=0;
 94 }
 95 int main()
 96 {int i,u,v,j,q;
 97  cin>>n;
 98  bin[0]=1;
 99  for (i=1;i<=20;i++)
100  bin[i]=bin[i-1]*2;
101   for (i=1;i<=n-1;i++)
102    {
103       scanf("%d%d",&u,&v);
104       add(u,v);add(v,u);
105    } 
106    dfs(1,0);
107    cin>>q;
108    while (q--)
109    {
110         k=gi();
111      M=k;
112         num=0;ans1=inf;ans2=0;
113         for (i=1;i<=k;i++)
114           a[i]=gi(),vis[a[i]]=1;
115         sort(a+1,a+k+1,cmp);
116         Lca=a[1];
117      for (i=2;i<=k;i++)
118        if (ed[a[i-1]]<dfn[a[i]])
119        a[++M]=lca(a[i-1],a[i]),Lca=lca(Lca,a[i]);
120        a[++M]=Lca;
121        sort(a+1,a+M+1,cmp);
122        M=unique(a+1,a+M+1)-a-1;
123        s[++top]=a[1];
124        for (i=2;i<=M;i++)
125        {
126            while (top&&ed[s[top]]<dfn[a[i]]) top--;
127            add2(s[top],a[i]);
128            s[++top]=a[i];
129        } 
130        dp(Lca);
131        printf("%lld %d %d\n",f[Lca],ans1,ans2);
132         for (i=1;i<=M;i++)
133         vis[a[i]]=head2[a[i]]=0;
134    }
135 }

 

以上是关于[HEOI2014]大工程的主要内容,如果未能解决你的问题,请参考以下文章

LibreOJ #2219. 「HEOI2014」大工程

bzoj 3611: [Heoi2014]大工程

[HEOI2014]大工程

[HEOI2014]大工程

[HEOI 2014]大工程

bzoj 3611: [Heoi2014]大工程