当前位置:首页 > 虚树 > 正文
BZOJ2286消耗战[SDOI2011]
1459+

题目大意:n个点的树,有m个特殊点,求结点1与特殊点不连通至少需要断开的边的最小长度,多组询问。

题目描述

在一场战争中,战场由 $n$ 个岛屿和 $n-1$ 个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为 $1$ 的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他 $k$ 个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。

侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到 $1$ 号岛屿上)。不过侦查部门还发现了这台机器只能够使用 $m$ 次,所以我们只需要把每次任务完成即可。

输入输出格式

输入格式

第一行一个整数 $n$,表示岛屿数量。

接下来 $n-1$ 行,每行三个整数 $u,v,w$ ,表示 $u$ 号岛屿和 $v$ 号岛屿由一条代价为 $w$ 的桥梁直接相连。

第 $n+1$ 行,一个整数 $m$ ,代表敌方机器能使用的次数。

接下来 $m$ 行,第 $i$ 行一个整数 $k_i$ ,代表第 $i$ 次后,有 $k_i$ 个岛屿资源丰富。接下来 $k_i$ 个整数 $h_1,h_2,…, h_{k_i}$ ,表示资源丰富岛屿的编号。

输出格式

输出共 $m$ 行,表示每次任务的最小代价。

输入输出样例

输入样例 #1

10
1 5 13
1 9 6
2 1 19
2 4 8
2 3 91
5 6 8
7 5 4
7 8 31
10 7 9
3
2 10 6
4 5 7 8 3
3 9 4 6

输出样例 #1

12
32
22

说明

#### 数据规模与约定

– 对于 $10\%$ 的数据,$n\leq 10, m\leq 5$ 。
– 对于 $20\%$ 的数据,$n\leq 100, m\leq 100, 1\leq k_i\leq 10$ 。
– 对于 $40\%$ 的数据,$n\leq 1000, 1\leq k_i\leq 15$ 。
– 对于 $100\%$ 的数据,$2\leq n \leq 2.5\times 10^5, 1\leq m\leq 5\times 10^5, \sum k_i \leq 5\times 10^5, 1\leq k_i< n, h_i\neq 1, 1\leq u,v\leq n, 1\leq w\leq 10^5$ 。

解题思路

树形DP暴力做法:结点1为根,f[a]记录结点a与子树a中特殊点端口的最小代价。对于儿子b,如果b是特殊点,那么连接a和b的边必须端口,否则要么b子树b无特殊点、特殊点已断开、断开当前边,即取min(f[b], c)。

这样做,每次询问都是O(n)的,会超时。注意到数据范围,所有询问特殊点数量之和不超过50万!能不能每次询问,只用特殊点进行转移?加入他们任意两点的LCA就行!因为特殊点与LCA之间的链,可以用倍增log的复杂度求出选哪条边断开。重构一棵只包含特殊点和他们LCA的树,就是构建虚树,这棵树的结点数量,不超过原来点树的2倍,因为两个点合并得到1个LCA而已,LCA可以代替他们继续找LCA。

虚树构建方法:按照DFS序依次构造虚树,需要先预处理每个结点的DFS序号,再按照序号权值排序。模拟DFS过程,根结点先加入“递归栈”,依次放入特殊点,如果特殊点是栈顶的子孙,那么先入栈,因为不确定他们之间是否还存在其他LCA结点;如果不是子孙,那么判断LCA是否在栈顶的2个元素之间,如果是,那么从栈顶结点回溯到LCA才会搜索到新结点,我们需要建立LCA到栈顶的边,然后把LCA和新结点入栈;否则LCA是更上面的结点,构建栈顶2个元素的边,继续重复前两个操作即可。注意,两个结点的边权,为原来的树两点间的最小边。

构造虚树巧妙之处:回溯弹栈时才连边,这样可以按照DFS序依次确定LCA。

程序实现

报歉!评论已关闭.