最近公共祖先
题意:
给你一个图,其中规定图上的一些边是这个图的一棵生成树的边
一个割如果只包含这棵树的一条边,那么它是一个尊敬割
问最小尊敬割(边没有权值)
数据范围:
点数<=20000,边数<=200000
思路:
首先我们知道不存在不包含这棵树任意边的割,因为如果不包含这棵树的任意边,则点肯定能通过这棵树连通
我们先暴力地想,先把生成树变成有根,然后枚举每个点,求每个点的特征值,这个特征值表示它的子树连到不是它的子树的点的边有多少条.那么,答案显然就是这些特征值的最小值(不包括根).
显然,暴力地求,对于每个点,需要扫描每条边,判断这条边是否符合要求,粗略地想复杂度是O(v2*e),显然不行
我们不从枚举点考虑,而是从边去考虑.我们把不是生成树的边称为多余边,每条多余边的加入会使若干个点的特征值+1,那么是哪些点呢?我们发现,每条多余边的加入,会和生成树的边构成一个环,而环上的点,特征值都会+1,除了公共祖先.所以我们可以扫描每条边,然后给这条边的两个端点在生成树的最短路径上的点(除了公共祖先)的特征值+1.这样的复杂度是O(ve)或者O(v2),还是不行
从上面可以看出这是树上的路径加一个值,类似于区间加一个值,这有点数据结构的意味了,我们现在要支持一种操作:给两个点,把这两个点在树上的路径上的所有点的特征值+1
我们可以联想到线段树的标记.每个点一个标记,刚开始是1(根是0或不管).然后每次加入一条多余边,我们就在边的两个端点给特征值+1.全部加入完后,我们从叶子往上传标记,父亲的标记=所有儿子的标记+自己的标记,然后再往上传.
这样有个问题,就是边的两端点的公共祖先都会算多了两次,所以我们给端点的特征值+1的时候,要找到它们的最近公共祖先,然后标记-2.这样最后传的时候,公共祖先会加减抵消,其他路径上的点就+1.这样做也意味着,我们要求某两点最近公共祖先,不过边是可以一次性读入,所以可以采用离线算法
最近公共祖先离线算法是O(e),加入每条边打标记是O(e),最后传标记和找答案是O(v).总的复杂度就是O(v+e).据说会卡nlogn
题意:
给你一个图,其中规定图上的一些边是这个图的一棵生成树的边
一个割如果只包含这棵树的一条边,那么它是一个尊敬割
问最小尊敬割(边没有权值)
数据范围:
点数<=20000,边数<=200000
思路:
首先我们知道不存在不包含这棵树任意边的割,因为如果不包含这棵树的任意边,则点肯定能通过这棵树连通
我们先暴力地想,先把生成树变成有根,然后枚举每个点,求每个点的特征值,这个特征值表示它的子树连到不是它的子树的点的边有多少条.那么,答案显然就是这些特征值的最小值(不包括根).
显然,暴力地求,对于每个点,需要扫描每条边,判断这条边是否符合要求,粗略地想复杂度是O(v2*e),显然不行
我们不从枚举点考虑,而是从边去考虑.我们把不是生成树的边称为多余边,每条多余边的加入会使若干个点的特征值+1,那么是哪些点呢?我们发现,每条多余边的加入,会和生成树的边构成一个环,而环上的点,特征值都会+1,除了公共祖先.所以我们可以扫描每条边,然后给这条边的两个端点在生成树的最短路径上的点(除了公共祖先)的特征值+1.这样的复杂度是O(ve)或者O(v2),还是不行
从上面可以看出这是树上的路径加一个值,类似于区间加一个值,这有点数据结构的意味了,我们现在要支持一种操作:给两个点,把这两个点在树上的路径上的所有点的特征值+1
我们可以联想到线段树的标记.每个点一个标记,刚开始是1(根是0或不管).然后每次加入一条多余边,我们就在边的两个端点给特征值+1.全部加入完后,我们从叶子往上传标记,父亲的标记=所有儿子的标记+自己的标记,然后再往上传.
这样有个问题,就是边的两端点的公共祖先都会算多了两次,所以我们给端点的特征值+1的时候,要找到它们的最近公共祖先,然后标记-2.这样最后传的时候,公共祖先会加减抵消,其他路径上的点就+1.这样做也意味着,我们要求某两点最近公共祖先,不过边是可以一次性读入,所以可以采用离线算法
最近公共祖先离线算法是O(e),加入每条边打标记是O(e),最后传标记和找答案是O(v).总的复杂度就是O(v+e).据说会卡nlogn
总结:维护每个点的特征值,每加入一条多余边,用打标记的方法给与生成树形成的环上的点的特征值+1.最后从叶子往上传标记,求特征值的最小值