大工程(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\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;
}
时间: 2024-08-01 19:54:44

大工程(bzoj 3611)的相关文章

bzoj 3611: [Heoi2014]大工程

Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径. 现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道. 现在对于每个计划,我们想知道: 1.这些新通道的代价和 2.这些新通道中代价最小的是多少 3.这些新通道中代价最大的是多少 Input 第一行 n

【BZOJ】【3611】【HEOI2014】大工程

虚树+树形DP 本题100W的点数……不用虚树真的好吗…… Orz ZYF 我的感悟: dp的过程跟SPOJ 1825 FTOUR2 的做法类似,依次枚举每个子树,从当前子树和之前的部分中各找一条最长(短)路径更新答案,再把这个子树的最短路径加入到x节点中去(之前算过的部分)这样就实现了枚举所有可能的最优情况!而且复杂度很低!避免了两两之间的枚举…… 1 /************************************************************** 2 Probl

[Bzoj3611][Heoi2014]大工程(虚树)

3611: [Heoi2014]大工程 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 2000  Solved: 837[Submit][Status][Discuss] Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径. 现在国家有很多个计划,每个计划都是这样,

【BZOJ3611】大工程(虚树,动态规划)

[BZOJ3611]大工程(虚树,动态规划) 题面 BZOJ Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径. 现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道. 现在对于每个计划,我们想知道: 1.这些新通道的代价和 2.这些新通道中代价最小的是多

LibreOJ #2219. 「HEOI2014」大工程

二次联通门 : LibreOJ #2219. 「HEOI2014」大工程 /* LibreOJ #2219. 「HEOI2014」大工程 虚树 + dp 对于每次的关键点建好虚树后 考虑树形dp dp[i] 表示在以i为根的子树路径总长 size[i] 表示在以i为根的子树中关键点的个数 maxn为以i为根的子树中到关键点到根最长的路径长 ans1自己推一推就好 对于ans2 如果i是关键点,则直接用maxn[i]更新答案 否则用maxn[i]+maxn[child[i]]+dis(i,son[

刷题总结——大工程(bzoj3611)

题目: Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径. 现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道. 现在对于每个计划,我们想知道: 1.这些新通道的代价和 2.这些新通道中代价最小的是多少 3.这些新通道中代价最大的是多少 Input 第一

Android Studio编译大工程报错:java.exe&#39;&#39; finished with non-zero exit value 1

版权声明:本文为博主原创文章,未经博主允许不得转载. Android Studio编译大工程报错:java.exe'' finished with non-zero exit value 1

[HEOI2014]大工程

题目描述 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径. 现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道.现在对于每个计划,我们想知道: 1.这些新通道的代价和 2.这些新通道中代价最小的是多少 3.这些新通道中代价最大的是多少 输入输出格式 输入格式: 第一行 n 表

BZOJ3611 [Heoi2014]大工程 【虚树】

题目 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径. 现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道. 现在对于每个计划,我们想知道: 1.这些新通道的代价和 2.这些新通道中代价最小的是多少 3.这些新通道中代价最大的是多少 输入格式 第一行 n 表示点数. 接下来