题目:

国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。

我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。

在 2 个国家 a,b 之间建一条新通道需要的代价为树上 a,b 的最短路径。

现在国家有很多个计划,每个计划都是这样,我们选中了 k 个点,然后在它们两两之间 新建 C(k,2)条 新通道。

现在对于每个计划,我们想知道:

1.这些新通道的代价和

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

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

题解:

这道题貌似是虚树的板子题.

为了这道题去学了学虚树.

因为我们发现我们只用在意两端都在关键点上的路径.

所以说实际上非关键点除了增加了一些路径的长度就没有其他的用处了.

我们可以考虑在原本的树上构造出一个只包括关键点但是赋予一定边一定的边权的与原树等价的树.

这就叫做虚树.

但是我们不能做到只保留关键点,我们仍然需要保留所有关键点之间的lca和lca之间的lca

对于虚树的构造方法有\(O(nlongn)\)的,可以去看其他的讲解,这里不再叙述.

随后我们在虚树上进行dp,考虑每一条边对答案的贡献即可.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
x=0;char ch;bool flag = false;
while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
const int maxn = 2100010;
const int inf = 0x3f3f3f3f;
ll f[maxn];int g[maxn][2];
int ans0,ans1,num;
bool col[maxn];
int son[maxn],top[maxn],dep[maxn];
int fa[maxn],dfn[maxn],dfs_clock;
struct Graph{
struct Edge{
int to,next;
}G[maxn<<1];
int head[maxn],cnt;
void add(int u,int v){
G[++cnt].to = v;
G[cnt].next = head[u];
head[u] = cnt;
}
int siz[maxn];
#define v G[i].to
void dfs(int u){
siz[u] = 1;
for(int i = head[u];i;i=G[i].next){
if(v == fa[u]) continue;
fa[v] = u;
dep[v] = dep[u] + 1;
dfs(v);
siz[u] += siz[v];
if(siz[son[u]] < siz[v]) son[u] = v;
}
}
void dfs(int u,int tp){
top[u] = tp;dfn[u] = ++ dfs_clock;
if(son[u]) dfs(son[u],tp);
for(int i = head[u];i;i=G[i].next){
if(v == fa[u] || v == son[u]) continue;
dfs(v,v);
}
}
void dp(int u,int fa){
if(col[u]) siz[u] = 1;
else siz[u] = 0;
f[u] = 0;g[u][0] = inf;g[u][1] = 0;
for(int i = head[u];i;i=G[i].next){
if(v == fa) continue;
dp(v,u);siz[u] += siz[v];
int d = dep[v] - dep[u];
f[u] += f[v] + 1LL*d*siz[v]*(num - siz[v]);
ans0 = min(ans0,g[u][0] + d + g[v][0]);
ans1 = max(ans1,g[u][1] + d + g[v][1]);
g[u][0] = min(g[u][0],d + g[v][0]);
g[u][1] = max(g[u][1],d + g[v][1]);
}
if(col[u]){
ans0 = min(ans0,g[u][0]);
ans1 = max(ans1,g[u][1]);
g[u][0] = 0;
}
head[u] = 0;
return ;
}
#undef v }pic1,pic2;
inline int lca(int u,int v){
while(top[u] != top[v]){
if(dep[top[u]] < dep[top[v]]) swap(u,v);
u = fa[top[u]];
}return dep[u] < dep[v] ? u : v;
}
int sta[maxn],a[maxn];
inline bool cmp(const int &i,const int &j){
return dfn[i] < dfn[j];
}
int main(){
int n;read(n);
for(int i=1,u,v;i<n;++i){
read(u);read(v);
pic1.add(u,v);
pic1.add(v,u);
}
pic1.dfs(1);pic1.dfs(1,1);
int q;read(q);
while(q--){
pic2.cnt = 0;
read(num);
for(int i=1;i<=num;++i){
read(a[i]);
col[a[i]] = true;
}
sort(a+1,a+num+1,cmp);
int top = 0;
for(int i=1;i<=num;++i){
if(top == 0) sta[++top] = a[i];
else{
int lc = lca(sta[top],a[i]);
while(dfn[sta[top]] > dfn[lc]){
if(dfn[sta[top-1]] <= dfn[lc]){
pic2.add(lc,sta[top]);
if(sta[--top] != lc)sta[++top] = lc;
break;
}
pic2.add(sta[top-1],sta[top]);
-- top;
}
sta[++top] = a[i];
}
}
while(top > 1) pic2.add(sta[top-1],sta[top]),top--;
ans0 = inf;ans1 = 0;
pic2.dp(sta[1],sta[1]);
printf("%lld %d %d\n",f[sta[1]],ans0,ans1);
for(int i=1;i<=num;++i) col[a[i]] = false;
}
return 0;
}

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

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

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

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

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

  3. bzoj 3611[Heoi2014]大工程 虚树+dp

    题意: 给一棵树 每次选 k 个关键点,然后在它们两两之间 新建 C(k,2)条 新通道. 求: 1.这些新通道的代价和 2.这些新通道中代价最小的是多少 3.这些新通道中代价最大的是多少 分析:较常 ...

  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. bzoj 3611: [Heoi2014]大工程 && bzoj 2286: [Sdoi2011消耗战

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

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

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

  8. bzoj 3611: [Heoi2014]大工程

    #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #d ...

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

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

随机推荐

  1. PHP、jQuery、AJAX和MySQL 数据库实例

    index.html页面 <!DOCTYPE html> <html lang="en"> <head> <meta charset=&q ...

  2. SDOI2012 Round1 day2 象棋(chess)解题报告

    本题的难点是“移动过程中不能出现多颗棋子同时在某一格的情况”. 事实上,可以忽略此条件,因为棋子是相同的,我们可以用合法的等效方案替代一棋子越过另一棋子的情况:A.B.C三格,A能在一步走到B,B也能 ...

  3. 新升级!EasyNVR3.0功能概述--直播与录像

    背景介绍: 对于摄像机直播已经是我们司空见惯的需求,但是,许多用户在现有的直播的基础上更有录像的需求,并且有关于录像的删除定时等录像计划的需求,更有客户不仅需要这些功能,还需要将这些功能集成到自身的业 ...

  4. 【学员管理系统】0x02 学生信息管理功能

    [学员管理系统]0x02 学生信息管理功能 写在前面 项目详细需求参见:Django项目之[学员管理系统] Django框架大致处理流程 捋一下Django框架相关的内容: 浏览器输入URL到页面展示 ...

  5. Django导出excel中文乱码解决方案

    Django官方文档有关于怎么生成csv文件的方法 import csv from django.http import HttpResponse def some_view(request): # ...

  6. linux c编程:非阻塞I/O

    通常来说,从普通文件读数据,无论你是采用 fscanf,fgets 也好,read 也好,一定会在有限的时间内返回.但是如果你从设备,比如终端(标准输入设备)读数据,只要没有遇到换行符(‘\n’),r ...

  7. ABAP下载服务器文件到本机

    转自http://blog.sina.com.cn/s/blog_701594f40100l8ml.html ABAP:下载服务器文件到本机 对服务器的文件进行读写操作,SAP提供了OPEN DATA ...

  8. php自定义的格式化时间示例代码

    时间刚好是5分钟前,则对应的时间戳就会被格式化为5分钟前,自定义的格式化时间方法如下,感兴趣的朋友可以参考下 如:时间刚好是5分钟前,则对应的时间戳就会被格式化为5分钟前,不多说了,直接贴上代码: 复 ...

  9. (转载)C#格式规范

    前言 之前工作中整理的一篇编码规范. 代码注释 注释约定 只在需要的地方加注释,不要为显而易见的代码加注释使用 /// 生成的xml标签格式的文档注释 方法注释 所有的方法都应该以描述这段代码的功能的 ...

  10. Linux服务器上的tomcat中部署web项目

    首先了解一下下面几个概念,讲得不太准确:1.JVMJVM是class以及jar(实际上就是很多个class压缩在一起)的运行环境,特征就是java和javaw命令,通过这两个命令,你可以执行class ...