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
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
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 }