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 ...
随机推荐
- Oracle笔记之用户管理
1. 创建用户 创建用户使用create user语句,需要DBA权限: CREATE USER tom IDENTIFIED BY mot; 2. 更改用户密码 修改别人的密码需要DBA权限,或者a ...
- Javascript装饰器的妙用
最近新开了一个Node项目,采用TypeScript来开发,在数据库及路由管理方面用了不少的装饰器,发觉这的确是一个好东西.装饰器是一个还处于草案中的特性,目前木有直接支持该语法的环境,但是可以通过 ...
- 蓝色的cms网站后台管理模板——后台
链接:http://pan.baidu.com/s/1c138cwC 密码:9vy9
- HTML标签学习之路-001
1.html的注释 <!--这里是注释内容--> <!--代表注释内容的开始 -->代表注释内容结束 注释部分,不会被浏览器输出,只是作为代码的说明,供开发者查阅 2.HTML ...
- salt-api起不来:ImportError('No module named wsgiserver2',)
问题:启动salt-api时没有报错但是没有端口,查看/var/log/salt/api发现如下报错: 解决方法: 下载wsgiserver2文件,放到/usr/lib64/python2.7/sit ...
- 浅谈Java中的hashcode方法(转)
原文链接:http://www.cnblogs.com/dolphin0520/p/3681042.html 浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地 ...
- Codefroces 919D Substring(拓扑排序+DP)
题目链接:http://codeforces.com/problemset/problem/919/D 题目大意:给你一张有向图,给你每个顶点上的字母和一些边,让你找出一条路径,路径上的相同字母数最多 ...
- javscript练习(三)
编写一个函数,计算两个数字的和差积商 function calculator(num1,num2,sign){ switch(sign){ cas ...
- GUC-4 CopyOnWriteArrayList/CopyOnWriteArraySet
/* * CopyOnWriteArrayList/CopyOnWriteArraySet : “写入并复制” * 注意:添加操作多时,效率低,因为每次添加时都会进行复制,开销非常的大.并发迭代操作多 ...
- Hadoop案例(二)压缩解压缩
压缩/解压缩案例 一. 对数据流的压缩和解压缩 CompressionCodec有两个方法可以用于轻松地压缩或解压缩数据.要想对正在被写入一个输出流的数据进行压缩,我们可以使用createOutput ...