题意:

给一棵树

每次选 k 个关键点,然后在它们两两之间 新建 C(k,2)条 新通道。

求:

1.这些新通道的代价和

2.这些新通道中代价最小的是多少

3.这些新通道中代价最大的是多少

分析:较常见的dp,详见代码

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
const int M=1000007;
using namespace std;
typedef long long LL;
const int INF=2147483647;
inline int rd(){
    int x=0;bool f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=0;
    for(;isdigit(c);c=getchar()) x=x*10+c-48;
    return f?x:-x;
}

int n,m;
int que[M];
int kd[M];

int dep[M];
int dfn[M],tdfn;
int ln[M<<1];
int a[M<<1][23],T;
int pos[M];

int g[M],te,hd[M],td;
struct edge{int y,next;}e[M<<1],dw[M];
void addedge(int x,int y){
    e[++te].y=y;e[te].next=g[x];g[x]=te;
}
void addlink(int x,int y){
    if(x==y) return;
    dw[++td].y=y;dw[td].next=hd[x];hd[x]=td;
}

int st[M],tot;
bool cmp(int x,int y){return dfn[x]<dfn[y];}

LL sz[M],sum[M];
int mx[M],mn[M];
LL ans;
int ansmn,ansmx;

void dfs(int x,int fa){
    a[pos[x]=++T][0]=x;
    dfn[x]=++tdfn;
    int p,y;
    for(p=g[x];p;p=e[p].next)
    if((y=e[p].y)!=fa){
        dep[y]=dep[x]+1;
        dfs(y,x);
        a[++T][0]=x;
    }
}

int gmn(int x,int y){return dep[x]<dep[y]?x:y;}

int LCA(int x,int y){
    x=pos[x],y=pos[y];
    if(x>y) swap(x,y);
    int l=ln[y-x+1];
    return gmn(a[x][l],a[y-(1<<l)+1][l]);
}

void init(){
    int i,j,l;
    for(i=2;i<=T;i++) ln[i]=ln[i>>1]+1;
    for(i=T;i>0;i--){
        l=ln[T-i+1];
        for(j=1;j<=l;j++) a[i][j]=gmn(a[i][j-1],a[i+(1<<j-1)][j-1]);
    }
}

int vbuild(int z){
    int rt;
    int i,x,anc;
    sort(que+1,que+z+1,cmp);
    rt=que[1];
    for(i=1;i<z;i++){
        x=LCA(que[i],que[i+1]);
        hd[x]=0; kd[x]=2; sz[x]=0; sum[x]=0; mn[x]=INF; mx[x]=-INF;
        if(dep[x]<dep[rt]) rt=x;
    }
    for(i=1;i<=z;i++){
        x=que[i];
        hd[x]=0; kd[x]=1; sz[x]=0; sum[x]=0; mn[x]=INF; mx[x]=-INF;
    }

    td=tot=0;
    st[++tot]=rt;
    for(i=1;i<=z;i++){
        x=que[i];
        anc=LCA(x,st[tot]);
        if(anc==st[tot]) st[++tot]=x;
        else{
            while( tot>1 && dep[anc]<=dep[st[tot-1]]){
                addlink(st[tot-1],st[tot]);
                tot--;
            }
            addlink(anc,st[tot]);
            st[tot]=anc;
            st[++tot]=x;
        }
    }
    for(i=1;i<tot;i++) addlink(st[i],st[i+1]);
    return rt;
}

void dp(int x){
    if(kd[x]==1) mn[x]=mx[x]=0,sz[x]=1;//****
    int p,y;
    LL d;
    for(p=hd[x];p;p=dw[p].next){
        y=dw[p].y;
        d=dep[y]-dep[x];
        dp(y);
        //能下面这样算就不要求最大次大,总的减子树这样复杂的东西
        ans+=sz[y]*sum[x];
        ans+=sz[x]*sum[y];
        ans+=sz[x]*sz[y]*d;
        if(mn[x]!=INF) ansmn=min(ansmn,mn[x]+mn[y]+(int)d);//注意越界
        if(mx[x]!=-INF) ansmx=max(ansmx,mx[x]+mx[y]+(int)d);

        sz[x]+=sz[y];
        sum[x]+=sum[y]+sz[y]*d;
        mn[x]=min(mn[x],mn[y]+(int)d);
        mx[x]=max(mx[x],mx[y]+(int)d);
    }
}

int main(){
    freopen("a.txt","r",stdin);
    int i,x,y,z;
    n=rd();
    for(i=1;i<n;i++){
        x=rd(),y=rd();
        addedge(x,y);
        addedge(y,x);
    }
    x=rand()%n+1;
    dep[x]=0;
    dfs(x,0);
    init();

    m=rd();
    while(m--){
        z=rd();
        for(i=1;i<=z;i++) que[i]=rd();
        x=vbuild(z);
        ans=0;
        ansmn=INF;
        ansmx=-INF;
        dp(x);
        printf("%lld %d %d\n",ans,ansmn,ansmx);
    }
    return 0;
}

bzoj 3611[Heoi2014]大工程 虚树+dp的更多相关文章

  1. BZOJ.3611.[HEOI2014]大工程(虚树 树形DP)

    题目链接 要求的和.最大值.最小值好像都可以通过O(n)的树形DP做,总询问点数<=2n. 于是建虚树就可以了.具体DP见DP()函数,维护三个值sum[],mx[],mn[]. sum[]要开 ...

  2. bzoj 3611: [Heoi2014]大工程 虚树

    题目: 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通道需要的代价为树上 ...

  3. BZOJ 3611 [Heoi2014]大工程 ——虚树

    虚树第二题.... 同BZOJ2286 #include <map> #include <cmath> #include <queue> #include < ...

  4. bzoj 3611 [Heoi2014]大工程(虚树+DP)

    3611: [Heoi2014]大工程 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 408  Solved: 190[Submit][Status] ...

  5. bzoj 3611(洛谷 4103) [Heoi2014]大工程——虚树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3611 https://www.luogu.org/problemnew/show/P4103 ...

  6. luogu P4103 [HEOI2014]大工程 虚树 + 树形 DP

    Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道.  我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上.  在 2 个国家 a,b 之间建一条新通 ...

  7. 洛谷P4103 [HEOI2014]大工程(虚树 树形dp)

    题意 链接 Sol 虚树. 首先建出虚树,然后直接树形dp就行了. 最大最小值直接维护子树内到该节点的最大值,然后合并两棵子树的时候更新一下答案. 任意两点的路径和可以考虑每条边两边的贡献,\(d[x ...

  8. [HEOI2014][bzoj3611] 大工程 [虚树+dp]

    题面: 传送门 思路: 又是一道虚树入门级的题目,但是这道题的实际难点在于dp 首先,这道题是可以点分治做的,而且因为6s时限随便浪,所以写点分治也不是不可以 但是,dp因为$O\left(n\rig ...

  9. bzoj 3611: [Heoi2014]大工程 && bzoj 2286: [Sdoi2011消耗战

    放波建虚树的模板. 大概是用一个栈维护根节点到当前关键点的一条链,把其他深度大于lca的都弹出去. 每次做完记得复原. 还有sort的时候一定要加cmp!!! bzoj 3611 #include&l ...

随机推荐

  1. tcp 重组原理

    原文: http://blog.chinaunix.net/uid-21768364-id-4823449.html 1 .引言TCP/IP 协议现在已经广泛的被应用.数据在网络上应用 TCP/IP ...

  2. script 两则

    script1: PATH=/usr/local/bin:/usr/bin:$PATH:. . $HOME/utility/macro/macro.env OVO_DIR=/tmp LOGFILE=$ ...

  3. 转:Selenium的延迟等待

    Selenium的延迟等待分为 显式等待(Explicit Wait) & 隐式等待(Implicit Wait). 1.显式等待 显式等待,就是明确的要等到某个元素的出现或者是某个元素的可点 ...

  4. java实现webservice

    第一步:web工程--新建server-config.wsdd 文件与web.xml同级 其内容如下 <?xml version="1.0" encoding="U ...

  5. POJ3352 Road Construction 双连通分量+缩点

    Road Construction Description It's almost summer time, and that means that it's almost summer constr ...

  6. WordPress主题制作第二天

    <?php if(have_posts()): while(have_posts()): the_post(); <!-- the_title(); the_permalink(); th ...

  7. [Big Data]Hadoop详解一

    从数据爆炸开始... 一. 第三次工业革命        第一次:18世纪60年代,手工工厂向机器大生产过渡,以蒸汽机的发明和使用为标志.      第二次:19世纪70年代,各种新技术新发明不断被应 ...

  8. Xcode7 免证书真机测试

    Xcode很早就有个免证书测试,今天我自己也测试了一把,还是挺好用的,接下来,我就说一下我的大体过程: 注意:一定要让你的真机设备的系统版本和app的系统版本想对应,如果不对应就会出现一个很常见的问题 ...

  9. hibernate---一对一单向外键关联--annotation (重要!!!)

    1. 生成wife.java: package com.bjsxt.hibernate; import javax.persistence.Entity; import javax.persisten ...

  10. 类似java.lang.NoClassDefFoundError: org/jaxen/JaxenException解决方法

    在使用dom4j的xpath时出现java.lang.NoClassDefFoundError: org/jaxen/JaxenException的异常,原因是dom4j引用了jaxen jar包,而 ...