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。
 

正解:虚树+树形dp。

对于每次询问,建立一棵虚树。在虚树上跑树形dp。这题有点麻烦,主要是dp的姿势吧。。求总数就是记录当前点size,然后加加减减就行了,求最小值就看当前点是否是关键点,如果是关键点就直接取它的子树路径最小值,否则就是它的两个儿子的子树路径最小值相加。求最大值同理。

 

 1 //It is made by wfj_2048~
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstring>
 5 #include <cstdlib>
 6 #include <cstdio>
 7 #include <vector>
 8 #include <cmath>
 9 #include <queue>
10 #include <stack>
11 #include <map>
12 #include <set>
13 #define inf (1<<30)
14 #define N (1000010)
15 #define il inline
16 #define RG register
17 #define ll long long
18 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
19 
20 using namespace std;
21 
22 struct edge{ int nt,to,dis; }g[2*N];
23 
24 int head[N],size[N],top[N],fa[N],son[N],dis[N],dep[N],dfn[N],ed[N],a[N],st[N],vi[N],sz[N],dp1[N],dp2[N],n,m,k,u,v,q,num,cnt,ans1,ans2;
25 ll dp[N];
26 
27 il int gi(){
28     RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar();
29     if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x;
30 }
31 
32 il void insert(RG int from,RG int to){ g[++num]=(edge){head[from],to},head[from]=num; return; }
33 
34 il int cmp(const int &a,const int &b){ return dfn[a]<dfn[b]; }
35 
36 il void dfs(RG int x){
37     dp[x]=0,dp1[x]=inf,dp2[x]=0,sz[x]=vi[x];
38     for (RG int i=head[x];i;i=g[i].nt){
39     RG int v=g[i].to,d=dis[v]-dis[x]; dfs(v);
40     sz[x]+=sz[v]; dp[x]+=dp[v]+(ll)sz[v]*(ll)(k-sz[v])*(ll)d;
41     ans1=min(ans1,dp1[x]+dp1[v]+d),dp1[x]=min(dp1[x],dp1[v]+d);
42     ans2=max(ans2,dp2[x]+dp2[v]+d),dp2[x]=max(dp2[x],dp2[v]+d);
43     }
44     if (vi[x]) ans1=min(ans1,dp1[x]),ans2=max(ans2,dp2[x]),dp1[x]=0;
45     head[x]=0; return;
46 }
47 
48 il void dfs1(RG int x,RG int p){
49     dfn[x]=++cnt,dep[x]=dep[p]+1,fa[x]=p,size[x]=1;
50     for (RG int i=head[x];i;i=g[i].nt){
51     RG int v=g[i].to; if (v==p) continue;
52     dis[v]=dis[x]+1; dfs1(g[i].to,x); size[x]+=size[v];
53     if (size[son[x]]<=size[v]) son[x]=v;
54     }
55     ed[x]=cnt; return;
56 }
57 
58 il void dfs2(RG int x,RG int p,RG int a){
59     top[x]=a; if (son[x]) dfs2(son[x],x,a);
60     for (RG int i=head[x];i;i=g[i].nt){
61     RG int v=g[i].to;
62     if (v==p || v==son[x]) continue;
63     dfs2(v,x,v);
64     }
65     head[x]=0; return;
66 }
67 
68 il int lca(RG int u,RG int v){
69     while (top[u]!=top[v]){
70     if (dep[top[u]]<dep[top[v]]) swap(u,v);
71     u=fa[top[u]];
72     }
73     return dep[u]<dep[v] ? u : v;
74 }
75 
76 il void work(){
77     n=gi(); for (RG int i=1;i<n;++i) u=gi(),v=gi(),insert(u,v),insert(v,u); dfs1(1,0),dfs2(1,0,1); q=gi();
78     for (RG int i=1;i<=q;++i){
79     k=gi(),m=k; for (RG int i=1;i<=k;++i) vi[a[i]=gi()]=1; sort(a+1,a+k+1,cmp); RG int Lca=a[1];
80     for (RG int i=2;i<=k;++i){ if (ed[a[i-1]]<dfn[a[i]]) a[++m]=lca(a[i-1],a[i]); Lca=lca(Lca,a[i]); }
81     a[++m]=Lca; sort(a+1,a+m+1,cmp); m=unique(a+1,a+m+1)-a-1; RG int top=1; st[top]=a[1],num=0;
82     for (RG int i=2;i<=m;++i){ while (top && ed[st[top]]<dfn[a[i]]) top--; insert(st[top],a[i]),st[++top]=a[i]; }
83     ans1=inf,ans2=0,dfs(Lca); printf("%lld %d %d\n",dp[Lca],ans1,ans2); for (RG int i=1;i<=m;++i) vi[a[i]]=0;
84     }
85     return;
86 }
87 
88 int main(){
89     File("project");
90     work();
91     return 0;
92 }

 

posted @ 2017-02-19 08:55  wfj_2048  阅读(132)  评论(0编辑  收藏  举报