ccz181078

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: :: 管理 ::

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

 

posted on 2017-05-18 17:25  nul  阅读(187)  评论(0编辑  收藏  举报