• 大工程(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

    Sample Output

    3 3 3
    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
    ",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;
    }
  • 相关阅读:
    双目对物体定位
    七个不变特征识别
    bmp和opencv格式转换
    职业规划
    input disp fprintf用法
    多线程
    访问权限
    机器人运动学仿真
    MOTOCOM32运动控制器编程
    回调函数以及钩子函数的概念
  • 原文地址:https://www.cnblogs.com/harden/p/6741169.html
Copyright © 2020-2023  润新知