算法学习——从bzoj2286开始的虚树学习生活
【原创】转载请标明原作者~
http://www.cnblogs.com/Acheing/
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2286
Description
在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。
侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到1号岛屿上)。不过侦查部门还发现了这台机器只能够使用m次,所以我们只需要把每次任务完成即可。
Input
第一行一个整数n,代表岛屿数量。
接下来n-1行,每行三个整数u,v,w,代表u号岛屿和v号岛屿由一条代价为c的桥梁直接相连,保证1<=u,v<=n且1<=c<=100000。
第n+1行,一个整数m,代表敌方机器能使用的次数。
接下来m行,每行一个整数ki,代表第i次后,有ki个岛屿资源丰富,接下来k个整数h1,h2,…hk,表示资源丰富岛屿的编号。
Output
输出有m行,分别代表每次任务的最小代价。
Sample Input
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
Sample Output
12
32
22
HINT
对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1
嗯。。无意中看到了这个题。。
然后。。就走上了一条不归路。。
首先,很方便就想到个暴力DP
设f[i][0]表示以i为根的子树,所有关键点都被切断的最小代价。
设f[i][1]表示以i为根的子树,与i相连的点未切断的最小代价。
然后,就发现这个DP可以写成这样:
设f[i]为以i为根的子树,所有i的父亲的关键点都被切断的最小代价。
那么转移方程就是f[i]=min(v[i],∑f[j]);j为i的儿子
于是乎。。
这个DP就变成n^2的了。。
然后,虚树就上场了!!!!
虚树是什么呢?
我发现再看一下这道题
发现有很多节点都是没有的!
例如样例中第一个问题,2,3,4,7,8,9号点都对答案没有影响。
(为什么7号点也没有影响?因为5-9的路径中选的边权(如果要选)肯定选4)
于是我们可以把原来的树缩成——
是的,虚树的用途就是将一棵树变成一棵新的树
且这棵树能包含所有需要的信息
---------------------------------------------------------------
but
怎么建虚树呢?
(以下将询问节点称为关键点)
1、将关键点按dfs序排序
2、将一个不会成为询问节点的点设为虚树的根节点,再将根节点放入栈中
3、将排好序的关键点依次加入栈中,然后。。
1)设当前点为x,栈顶元素为p,q为lca(x,p)
2)若q=p,则将p加入栈中(为什么q!=x?如果q==x则dfn[x]<dfn[p]然而因为排序过了所以dfn[x]必定小于dfn[p])
3)若q!=p,说明x和p在两棵子树中。。则再次分类讨论。。(设dfn[i]为i的dfs序号,y为栈顶下面那个元素,即如果进行一次弹出操作,y为栈顶)
1】若dfn[y]>dfn[q]说明q还在y上面,则在虚树中add(p,y)再进行一次弹出操作。
2】若dfn[y]=dfn[q]说明y已经是lca了,则直接在虚树中add(p,y)再进行一次弹出操作,然后。。就直接跳到4)就行了。
3】若dfn[y]<dfn[q]说明!!y已经在q上面了(待会会给出例子),就add(q,p),弹出一次,再将q加入栈中。
4)然后将x加入栈中。重复以上操作即可
这样构建出来的虚树,节点一定是最少的
虚树上(x,y)的边权就是(x,y)在原树上的路径中边权的最小值,可以用树链剖分或倍增来维护。
---------------------------------------------------------------
再画些图~
啊哦有点大T_T
反正就是这样,建完虚树后,就可以直接DP了,是不是超神奇!
写在最后
1、一棵树上k个点的lca最多只有k-1个,所以一次DP复杂度是O(k)的,空间也是(但要*2!)。
2、归纳一下,只有在非关键点不影响结果的情况下才能用虚树。
3、其实树的形态不固定也可以建虚树。
4、有些证明什么的。。可以去看xyz大爷的论文
5、至于代码。。
然后,就完结了!
难得写这么认真。。
参考资料:http://www.cnblogs.com/chenhuan001/p/5639482.html