算法学习——从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<=n1<=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

posted @ 2017-05-27 10:55  Acheing  阅读(249)  评论(0编辑  收藏  举报