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 ...
随机推荐
- webview300毫秒点击问题
http://www.jshacker.com/note/3585 http://blog.csdn.net/zfy865628361/article/details/49512095 http:// ...
- task10-14
[说明]今天白天有事外出了,晚上会图书馆做了下面的任务,时间有点紧,好多没完成,明天要补上今天的! 一:今日完成 10.插入10条数据,查看有索引和无索引的情况下,Sql语句执行的效率 1)插入数据时 ...
- sql 语句实现分页查询
SELECT * FROM ( SELECT A.*, ROWNUM RN FROM (SELECT * FROM TABLE_NAME) A WHERE ROWNUM <= 40 ) WHER ...
- 九度OJ 1251:序列分割 (DFS)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:166 解决:34 题目描述: 一个整数数组,长度为n,将其分为m份,使各份的和相等,求m的最大值 比如{3,2,4,3,6} 可以分成{ ...
- mybatis相关
1 namespace dao中使用namespace+id一起来完成对mapper中sql statement的调用. 2 关于resultMap和parameterType parameterTy ...
- JDBC【菜鸟学JAVA】
1:首先下载sqljdbc.jar,然后配置ClassPath,然后再在工程文件中把这个(sqljdbc.jar)架包引用上,就可以开始JAVA操作之旅了 打开Eclipse,“文件”→“新建”→“项 ...
- Windows存储管理之磁盘结构详解
Windows磁盘结构: Windows的主流磁盘结构分为MBR和GPT两种.MBR是早期Windows的唯一选择,但是随着物理磁盘的容量不断增大.GPT结构成为目前的主流,最大支持超过2TB的容量, ...
- LeetCode:柠檬水找零【860】
LeetCode:柠檬水找零[860] 题目描述 在柠檬水摊上,每一杯柠檬水的售价为 5 美元. 顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯. 每位顾客只买一杯柠檬水,然后向 ...
- C#快速入门笔记(1)——基础语法
C#快速入门笔记(1)——基础语法 总体框架:
- 每天一个Linux命令(34)grep命令
grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具 ...