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 行,每行三个数分别表示代价和,最小代价,最大代价。
建出虚树,在上面树形dp求一下关键点之间的最近、最远距离,距离和。
虚树不需要真正建出来并连边,只要保留虚树中点按dfs序排序后的数组即可在上面dfs
#include<cstdio> #include<algorithm> const int N=1.01e6+7,inf=0x3f3f3f3f; int n,m; int es[N*2],enx[N*2],e0[N],ep=2,stk[N],stp=0; int fa[N],sz[N],son[N],top[N],dep[N],id[N],id2[N],idr[N],idp=0,ps[N]; int ed[N],tk=0; void hld_pre(){ idr[id[1]=++idp]=stk[++stp]=1; for(int i=1;i<=n;++i)sz[i]=1; while(stp){ int w=stk[stp],&e=e0[w]; if(!e){ --stp; id2[w]=idp; int f=fa[w]; sz[f]+=sz[w]; if(sz[w]>sz[son[f]])son[f]=w; continue; } int u=es[e];e=enx[e]; if(u==fa[w])continue; fa[idr[id[u]=++idp]=stk[++stp]=u]=w; dep[u]=dep[w]+1; } for(int t=1;t<=idp;++t){ int w=idr[t],f=fa[w]; top[w]=(son[f]==w?top[f]:w); } } int lca(int x,int y){ int a=top[x],b=top[y]; while(a!=b){ if(dep[a]>dep[b])x=fa[a],a=top[x]; else y=fa[b],b=top[y]; } return dep[x]<dep[y]?x:y; } inline int cmp(int a,int b){return id[a]<id[b];} int mx[N][2],mn[N][2],FA[N],pp,SZ[N]; long long sum[N]; void push(){ int w=stk[++stp]=pp++; sum[w]=0; mx[w][1]=-inf; mn[w][1]=inf; if(ed[ps[w]]==tk){ SZ[w]=1; mx[w][0]=0; mn[w][0]=0; }else{ SZ[w]=0; mx[w][0]=-inf; mn[w][0]=inf; } } void mxs(int*a,int b){ if(b>=a[0])a[1]=a[0],a[0]=b; else if(b>a[1])a[1]=b; } void mns(int*a,int b){ if(b<=a[0])a[1]=a[0],a[0]=b; else if(b<a[1])a[1]=b; } void mxs(int&a,int b){if(a<b)a=b;} void mns(int&a,int b){if(a>b)a=b;} void dfs(){ long long ans=0; pp=0; int mxv=-inf,mnv=inf; push(); while(stp){ int x=stk[stp]; if(pp<m&&id[ps[pp]]<=id2[ps[x]]){ FA[pp]=x; push(); }else{ --stp; if(x){ int f=FA[x],e=dep[ps[x]]-dep[ps[f]]; mxs(mx[f],mx[x][0]+e); mns(mn[f],mn[x][0]+e); long long s1=sum[x]+e*(long long)SZ[x]; ans+=sum[f]*SZ[x]+s1*SZ[f]; SZ[f]+=SZ[x]; sum[f]+=s1; } mxs(mxv,mx[x][0]+mx[x][1]); mns(mnv,mn[x][0]+mn[x][1]); } } printf("%lld %d %d\n",ans,mnv,mxv); } int main(){ scanf("%d",&n); for(int i=1,a,b;i<n;++i){ scanf("%d%d",&a,&b); es[ep]=b;enx[ep]=e0[a];e0[a]=ep++; es[ep]=a;enx[ep]=e0[b];e0[b]=ep++; } hld_pre(); int T; for(scanf("%d",&T);T;--T){ scanf("%d",&m); ++tk; for(int i=0;i<m;++i)scanf("%d",ps+i),ed[ps[i]]=tk; std::sort(ps,ps+m,cmp); for(int i=m-1;i;--i){ int x=lca(ps[i-1],ps[i]); if(ed[x]!=tk)ps[m++]=x; } std::sort(ps,ps+m,cmp); ps[m]=0; dfs(); } return 0; }