大工程(bzoj 3611)
Posted Cola
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了大工程(bzoj 3611)相关的知识,希望对你有一定的参考价值。
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
/* f[i]表示以i为根的子树的路径和 f[i]=f[son[i]]+siz[son[y]]*(cnt-siz[son[y]])*dis(i,son[i]) maxs[i]表示以i为根的子树的节点到i的最大长度 用maxs[i]+maxs[son[i]]+dis(i,son[i])来更新答案。 然后在虚树上做DP */ #include<iostream> #include<cstdio> #include<algorithm> #define N 1000010 #define lon long long #define inf 1000000000 using namespace std; int n,m,dfn[N],dep[N],tim,fa[N][21],a[N],num; int g[N],sta[N],top,siz[N],mins[N],maxs[N],ans1,ans2; lon f[N]; bool cmp(int x,int y){return dfn[x]<dfn[y];} struct Node{ int head[N],son[N*2],pre[N*2],cnt; void add(int u,int v){ son[++cnt]=v;pre[cnt]=head[u];head[u]=cnt; } void dfs1(int u){ dfn[u]=++tim; for(int i=1;i<=20;i++) fa[u][i]=fa[fa[u][i-1]][i-1]; for(int i=head[u];i;i=pre[i]) if(son[i]!=fa[u][0]){ fa[son[i]][0]=u; dep[son[i]]=dep[u]+1; dfs1(son[i]); } } void dfs2(int x){ siz[x]=g[x];maxs[x]=0;mins[x]=inf;f[x]=0; for(int i=head[x];i;i=pre[i]){ int d=dep[son[i]]-dep[x]; dfs2(son[i]);siz[x]+=siz[son[i]]; ans1=min(ans1,mins[x]+mins[son[i]]+d); mins[x]=min(mins[x],mins[son[i]]+d); ans2=max(ans2,maxs[x]+maxs[son[i]]+d); maxs[x]=max(maxs[x],maxs[son[i]]+d); f[x]+=f[son[i]]+1LL*siz[son[i]]*(num-siz[son[i]])*d; } if(g[x]) ans1=min(ans1,mins[x]),ans2=max(ans2,maxs[x]),mins[x]=0; head[x]=0; } }g1,g2; int lca(int a,int b){ if(dep[a]<dep[b]) swap(a,b); int t=dep[a]-dep[b]; for(int i=20;~i;i--) if(t&(1<<i)) a=fa[a][i]; if(a==b) return a; for(int i=20;~i;i--) if(fa[a][i]!=fa[b][i]) a=fa[a][i],b=fa[b][i]; return fa[a][0]; } void work(){ top=0; for(int i=1;i<=num;i++){ if(!top){sta[++top]=a[i];continue;} int anc=lca(a[i],sta[top]); while(dep[anc]<dep[sta[top]]){ if(dep[anc]>=dep[sta[top-1]]){ g2.add(anc,sta[top]); top--; if(sta[top]!=anc) sta[++top]=anc; break; } else g2.add(sta[top-1],sta[top]),top--; } if(sta[top]!=a[i]) sta[++top]=a[i]; } while(top>1) g2.add(sta[top-1],sta[top]),top--; ans1=inf;ans2=0;g2.dfs2(sta[1]); printf("%lld %d %d\n",f[sta[1]],ans1,ans2); for(int i=1;i<=num;i++) g[a[i]]=0;g2.cnt=0; } int main(){ scanf("%d",&n); for(int i=1;i<n;i++){ int u,v;scanf("%d%d",&u,&v); g1.add(u,v);g1.add(v,u); } g1.dfs1(1);scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%d",&num); for(int j=1;j<=num;j++) scanf("%d",&a[j]),g[a[j]]=1; sort(a+1,a+num+1,cmp); work(); } return 0; }
以上是关于大工程(bzoj 3611)的主要内容,如果未能解决你的问题,请参考以下文章