题链:
https://www.luogu.org/problemnew/show/P3233
题解:
虚树,dp,倍增。
首先对于每个询问,要把虚树建出来,这一步就从略了。这里着重分享一下如何求答案。
比如,我们建出来如下一颗虚树,给出的关键点是那些黑点点们,红点点是"被迫"加入的LCA
然后,我们就要去求每个黑点的答案了!
等等,YY了一会儿,发现好像现在还并不方便直接求。
那么我们一步一步来,先求出这颗虚树上的每个节点属于哪个黑点管辖(到哪个黑点最近)。
用near[u]表示距离u点最近的黑点是哪个,dis[u]表示u点到near[u]的距离
怎么做呢?
首先,赋一下初值,然后两个dp,就完了。
首先,黑点的当然被自己管辖,所以near[u]=u,dis[u]=0
然后进行第一个dp,我们尝试用儿子v去更新其父亲u。
if dis[u]>dis[v]+e[u->v] then near[u]=near[v],dis[u]=dis[v]+e[u->v]
这个e[u->v]就是u到v的距离,在建虚树时得到。
然后进行第二个dp,我们尝试用父亲u去更新儿子v。
if dis[v]>dis[u]+e[u->v] then near[v]=near[u],dis[v]=dis[u]+e[u->v]
这样之后,就得到这颗虚树正确的near[]和dis[],
换句话说,我们已经知道了原树上的最最最关键的那些点究竟是属于哪个黑点管辖的。
接下来就是看如何处理得到其它点。
我们先把虚树画再详细一点:
棕色的点就是被虚树省略掉的不重要的点,
而现在我们需要确定的就是这些点会给那些黑点贡献答案。
显然我们不能一个一个地去考虑棕色的点。
但是注意到,所有棕色的节点都是从虚树的边上长出来的,
所以我们的做法是依次考虑每条虚树的边:
代码:
原文地址:https://www.cnblogs.com/zj75211/p/8552270.html