bzoj 2286
第一道"虚树"题目(好吧,我也不知道这是不是虚树,但和虚树的思想肯定是一样的,都是简化树结构)
这一类算法核心思想都是简化树结构,只取我们必须的节点和一些信息,然后在简化后的树结构上工作。
首先,如果这道题只有一次询问,那么很容易想到树形DP的解法,但这道题又多组询问,并且限制了所有询问的关键点个数,这意味着我们必须设计出一种算法,她回答一组询问的复杂度只和关键点个数相关(O(k)或O(klogk)都是可接受的),而和原图无关(最多加个logn)。
然后就有了虚树,我们可以构建一个新的树,这棵树上有所有关键点,以及相邻dfs序上相邻的两个关键点的lca,我们发现,这样的图包括了所有关键点的lca以及所有关键点,然后改一下DP就可以在这棵树上快速的搞了(因为节点个数是O(2*k),所以这样DP的复杂度就从O(n)变成了O(k))。
DP:
dp[i]表示将i及其子树中所有关键点与跟节点断开所需的最小代价(可以砍他们上面的边)
构简化图:
对于一个询问,我们先将其关键点按照DFS序排序。然后维护一个栈保存当前走了的关键点或关键点之间的LCA,当我们要插入一个新的关键节点时,我们根据当前节点与当前栈顶节点LCA的深度与栈顶元素的深度来判断是否需要弹出节点,一直弹出,直到深度大于等于栈顶元素(注意,这个LCA是最初的栈顶与新的关键节点的LCA)
/**************************************************************
Problem: 2286
User: idy002
Language: C++
Result: Accepted
Time:6700 ms
Memory:32060 kb
****************************************************************/ #include <cstdio>
#include <vector>
#include <algorithm>
#define min(a,b) ((a)<(b)?(a):(b))
#define oo 0x3f3f3f3f
#define N 250010
#define P 17
using namespace std; typedef long long dnt; int n, m;
int head[N], dest[N+N], wght[N+N], next[N+N], ntot;
int dfn[N], dep[N], bst[N], anc[N][P+], idc;
int qcnt, aa[N], stk[N], top;
dnt dp[N]; void adde( int u, int v, int w ) {
ntot++;
wght[ntot] = w;
dest[ntot] = v;
next[ntot] = head[u];
head[u] = ntot;
}
void dfs( int u ) {
dfn[u] = ++idc;
for( int p=; p<=P; p++ )
anc[u][p] = anc[anc[u][p-]][p-];
for( int t=head[u]; t; t=next[t] ) {
int v=dest[t], w=wght[t];
if( v==anc[u][] ) continue;
anc[v][] = u;
bst[v] = min( bst[u], w );
dep[v] = dep[u]+;
dfs(v);
}
}
bool cmp( int u, int v ) {
return dfn[u]<dfn[v];
}
int lca( int u, int v ) {
if( dep[u]<dep[v] ) swap(u,v);
int t=dep[u]-dep[v];
for( int p=; t; t>>=,p++ )
if( t& ) u=anc[u][p];
if( u==v ) return u;
for( int p=P; p>= && anc[u][]!=anc[v][]; p-- )
if( anc[u][p]!=anc[v][p] )
u=anc[u][p], v=anc[v][p];
return anc[u][];
}
void sov() {
scanf( "%d", &qcnt );
for( int i=; i<=qcnt; i++ )
scanf( "%d", aa+i );
sort( aa+, aa++qcnt, cmp ); stk[top=] = ;
dp[] = ;
for( int i=; i<=qcnt; i++ ) {
int ca=lca(aa[i],stk[top]);
while( dep[stk[top]]>dep[ca] ) {
int fa, u;
u = stk[top];
top--;
if( dep[stk[top]]<=dep[ca] ) {
if( dep[stk[top]]<dep[ca] ) {
stk[++top] = ca;
dp[ca] = ;
}
fa = stk[top]; dp[u] = min( dp[u], bst[u] );
dp[fa] += dp[u];
break;
}
fa = stk[top]; dp[u] = min( dp[u], bst[u] );
dp[fa] += dp[u];
}
int u=aa[i];
stk[++top] = u; dp[u] = bst[u];
}
while( top ) {
if( top- ) {
int fa=stk[top-], u=stk[top]; dp[u] = min( dp[u], bst[u] );
dp[fa] += dp[u];
}
top--;
}
printf( "%lld\n", dp[] );
}
int main() {
scanf( "%d", &n );
for( int i=,u,v,w; i<n; i++ ) {
scanf( "%d%d%d", &u, &v, &w );
adde( u, v, w );
adde( v, u, w );
}
anc[][] = ;
dep[] = ;
bst[] = oo;
dfs();
scanf( "%d", &m );
for( int i=; i<=m; i++ )
sov();
}
bzoj 2286的更多相关文章
- BZOJ 2286: [Sdoi2011]消耗战
2286: [Sdoi2011消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2082 Solved: 736[Submit][Status] ...
- bzoj 2286 [Sdoi2011]消耗战(虚树+树上DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2286 [题意] 给定一棵树,切断一条树边代价为ci,有m个询问,每次问使得1号点与查询 ...
- bzoj 2286: [Sdoi2011]消耗战 虚树+树dp
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...
- bzoj 2286(洛谷 2495) [Sdoi2011]消耗战——虚树
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2286 https://www.luogu.org/problemnew/show/P2495 ...
- bzoj 3611: [Heoi2014]大工程 && bzoj 2286: [Sdoi2011消耗战
放波建虚树的模板. 大概是用一个栈维护根节点到当前关键点的一条链,把其他深度大于lca的都弹出去. 每次做完记得复原. 还有sort的时候一定要加cmp!!! bzoj 3611 #include&l ...
- BZOJ 2286: [Sdoi2011]消耗战 虚树 树形dp 动态规划 dfs序
https://www.lydsy.com/JudgeOnline/problem.php?id=2286 wa了两次因为lca犯了zz错误 这道题如果不多次询问的话就是裸dp. 一棵树上多次询问,且 ...
- BZOJ.2286.[SDOI2011]消耗战(虚树 树形DP)
题目链接 BZOJ 洛谷P2495 树形DP,对于每棵子树要么逐个删除其中要删除的边,要么直接断连向父节点的边. 如果当前点需要删除,那么直接断不需要再管子树. 复杂度O(m*n). 对于两个要删除的 ...
- Bzoj 2286 & Luogu P2495 消耗战(LCA+虚树+欧拉序)
题面 洛谷 Bzoj 题解 很容易想到$O(nk)$的树形$dp$吧,设$f[i]$表示处理完这$i$颗子树的最小花费,同时再设一个$mi[i]$表示$i$到根节点$1$路径上的距离最小值.于是有: ...
- bzoj 2286(虚树+树形dp) 虚树模板
树链求并又不会写,学了一发虚树,再也不虚啦~ 2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5002 Sol ...
随机推荐
- HDU 1754 I Hate It (线段树)
题目链接 Problem Description 很多学校流行一种比较的习惯.老师们很喜欢询问,从某某到某某当中,分数最高的是多少. 这让很多学生很反感. 不管你喜不喜欢,现在需要你做的是,就是按照老 ...
- python 天气爬虫
python3 爬取全国天气信息 制作一个天气查询软件,能够查询全国范围内的天气数据. github:https://github.com/1052687889/weatherApp 基于PyQt5编 ...
- Java企业级电商项目架构演进之路 Tomcat集群与Redis分布式
史诗级Java/JavaWeb学习资源免费分享 欢迎关注我的微信公众号:"Java面试通关手册"(坚持原创,分享各种Java学习资源,面试题,优质文章,以及企业级Java实战项目回 ...
- INIT_WORK
借助runtime pm,在需要使用模块时,增加引用计数(可调用pm_runtime_get),不需要使用时,减少引用计数(可调用pm_runtime_put). 1.INIT_WORK(struct ...
- elk系列8之logstash+redis+es的架构来收集apache的日志【转】
preface logstash--> redis --> logstash --> es这套架构在讲究松耦合关系里面是最简单的,架构图如下: 解释下这个架构图的流程 首先前端log ...
- Swift中的指针类型
Swift编程语言为了能与Objective-C与C语言兼容,而引入了指针类型.尽管官方不建议频繁使用指针类型,但很多时候,使用指针能完成更多.更灵活的任务.比如,我们要实现一个交换两个整数值的函数的 ...
- windows 下 nginx 配置虚拟主机
1. 在 nginx 的配置文件 nginx.conf 里面 引入虚拟主机配置文件,以后所有的虚拟主机配置文件都在写这个文件里 include vhost.conf; (或者新建vhost ...
- Spring 中Bean的装配方式
最近又买了一本介绍SSM框架的书,是由黑马程序员编写的,书上讲的很好理解,边看边总结一下.主要总结一下bean的装配方式. Bean的装配可以理解为依赖系统注入,Bean的装配方式即Bean依赖注入的 ...
- day4 迭代器与生成器解析
一.迭代器 迭代器是访问集合元素的一种方式.其实迭代器就是一种列表,只是访问集合元素的时候比较特殊,具有一些特定功能,记忆功能,能够记住用户上一次的状态.迭代器是访问集合元素的一种方式.并且,迭代器只 ...
- LoadRunner学习笔记log函数
lr_log_message 只是记会写到本地vuser的log里面. lr_message和lr_output_message基本相同,它们会同时写到vuser的log和发送到controller里 ...