【树上点分治】
·算法步骤:
·实际应用说明:(POJ-1741)
给你一棵包含n(n<20001)个结点的带权无向树。
给定一个limit(limit<10^9),并读入每条边的端点和权值。
令dis(u,v)为两点之间的路径长度,输出对于任意u,v的dis(u,v)的值小于等于limit的组数。
·从简单情况入手:
这个树只有两层,那么每个点之间的路径必定含有根节点(如图):
使用一种处理方法来快速求解:
将每个结点到根节点的距离(当然,在这个图中,距离就是边权)塞入一个a数组。然后sort(a+1,a+5+1)。启用l(init:1),r(init:5)作为左右标记。假定几个w的大小关系为:W1<W2<W3<W4<W5。那么对a数组进行如下操作,可以快速得出路径小于等于limit的组数:
(注:图片中K即limit)
·处理现实情况:
上图中的叶子节点变成一棵棵子树,就成了普遍的情况。用开始的方法求解貌似可以,只不过是需要递归地去找每一个节点到根节点的距离,而不是简单的边权了。但这样出现了一个局限性:这样找出的答案的意义是两个点之间的路径必须经过根节点,但并不是所有答案都经过这个节点。并且,由于a数组里面此时包含了来自各个子树的节点,所以会出现这样的不合法路径:一个点走到根节点,然后又从根节点走回自己原来所在的子树并且跟这其中的一个节点形成路径。所以要做两件事情来弥补。第一,答案不完全,需要通过分治让子树向根节点贡献答案。第二,ans1计算中有部分非法情况(即来自同一子树的两个点之间的路径)。
·解决ans1卡机的方法是枚举每个子树,并以子树的根为根,初始权值为父节点到它的权值(表示要算上这条边的边权),按同样的方法求出ans2。每一次枚举都进行:ans-=ans2;
·这一切说来像树形DP。
(注:树的重心是指所有节点中,以某点为根节点时其节点数最大的子树的节点数最小的那个节点。这样是为了让树保持美妙)
·接下来有一个同类型但处理方式不同的点分治问题:
·【聪可聪可】(BZOJ-2152)
求出dis(u,v)为3的倍数的组数(不过这里(1,2)(2,1)算两组)。
I promise you,that our bond will never die,until my pain is vast as the sky.
——汪峰《Song Of Redemption》