bzoj 3611: [Heoi2014]大工程 虚树
题目:
国家有一个大工程,要给一个非常大的交通网络里建一些新的通道。
我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上。
在 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]大工程 虚树的更多相关文章
- BZOJ.3611.[HEOI2014]大工程(虚树 树形DP)
题目链接 要求的和.最大值.最小值好像都可以通过O(n)的树形DP做,总询问点数<=2n. 于是建虚树就可以了.具体DP见DP()函数,维护三个值sum[],mx[],mn[]. sum[]要开 ...
- BZOJ 3611 [Heoi2014]大工程 ——虚树
虚树第二题.... 同BZOJ2286 #include <map> #include <cmath> #include <queue> #include < ...
- bzoj 3611[Heoi2014]大工程 虚树+dp
题意: 给一棵树 每次选 k 个关键点,然后在它们两两之间 新建 C(k,2)条 新通道. 求: 1.这些新通道的代价和 2.这些新通道中代价最小的是多少 3.这些新通道中代价最大的是多少 分析:较常 ...
- bzoj 3611 [Heoi2014]大工程(虚树+DP)
3611: [Heoi2014]大工程 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 408 Solved: 190[Submit][Status] ...
- bzoj 3611(洛谷 4103) [Heoi2014]大工程——虚树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3611 https://www.luogu.org/problemnew/show/P4103 ...
- bzoj 3611: [Heoi2014]大工程 && bzoj 2286: [Sdoi2011消耗战
放波建虚树的模板. 大概是用一个栈维护根节点到当前关键点的一条链,把其他深度大于lca的都弹出去. 每次做完记得复原. 还有sort的时候一定要加cmp!!! bzoj 3611 #include&l ...
- luogu P4103 [HEOI2014]大工程 虚树 + 树形 DP
Description 国家有一个大工程,要给一个非常大的交通网络里建一些新的通道. 我们这个国家位置非常特殊,可以看成是一个单位边权的树,城市位于顶点上. 在 2 个国家 a,b 之间建一条新通 ...
- bzoj 3611: [Heoi2014]大工程
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #d ...
- 洛谷P4103 [HEOI2014]大工程(虚树 树形dp)
题意 链接 Sol 虚树. 首先建出虚树,然后直接树形dp就行了. 最大最小值直接维护子树内到该节点的最大值,然后合并两棵子树的时候更新一下答案. 任意两点的路径和可以考虑每条边两边的贡献,\(d[x ...
随机推荐
- python 深复制与浅复制------copy模块
模块解读: 浅复制: x = copy.copy(y)深复制: x = copy.deepcopy(y)(注:模块特有的异常,copy.Error) 深copy与浅copy的差别主要体现在当有混合对象 ...
- 【BZOJ2728】[HNOI2012]与非 并查集+数位DP
[BZOJ2728][HNOI2012]与非 Description Input 输入文件第一行是用空格隔开的四个正整数N,K,L和R,接下来的一行是N个非负整数A1,A2……AN,其含义如上所述. ...
- 像使用linux一样使用mac
1 不能像使用windows一样使用mac 因为mac卸载不方便. 2 gcc的问题 就使用系统默认的gcc,即clang,要想使用原声的gcc是不行的,mac本身不支持.
- [JavaScript]WebBrowser控件下IE版本的检测
转载请注明原文地址:https://www.cnblogs.com/litou/p/10772272.htm 在客户端检查用户使用的浏览器类型和版本,都是根据navigator.userAgent属性 ...
- Pipeline outbound
netty源码死磕8 Pipeline outbound 出站流程揭秘 1. Pipeline outbound流程 1.1. 出站的定义 简单回顾一下. 出站(outbound) 操作,通常是处于上 ...
- Card Collector(期望+min-max容斥)
Card Collector(期望+min-max容斥) Card Collector woc居然在毫不知情的情况下写出一个min-max容斥 题意 买一包方便面有几率附赠一张卡,有\(n\)种卡,每 ...
- Linux项目部署发布
Linux项目部署发布 1.部署环境准备,准备python3和虚拟环境解释器,virtualenvwrapper pip3 install -i https://pypi.douban.com/sim ...
- 存储过程 & 触发器
触发器主要是通过事件进行触发而被执行的,而存储过程可以通过存储过程名字而被直接调用.当对某一表进行诸如UPDATE. INSERT. DELETE 这些操作时, 就会自动执行触发器所定义的SQL 语句 ...
- linux c编程:进程控制(四)进程关系
每一个进程除了有一个进程ID外,还属于一个进程组. 进程组是一个或多个进程的集合,通常情况下,他们是在同一作业中结合起来的,同一进程组的个进程接受来自同一终端的各种信号. 每一个进程组有一个唯一的进 ...
- KVM虚拟化技术实战全过程
今天准备开始.................... centos安装-kvm 教程: http://www.linuxidc.com/Linux/2017-01/140007.htm http:// ...