HDU6031 Innumerable Ancestors 倍增 - 题意详细概括 - 算法详解
题目
查看原题 - HDU6031 Innumerable Ancestors
题目描述
有一棵有n个节点的有根树,根节点为1,其深度为1,现在有m个询问,每次询问给出两个集合A和B,问LCA(x,y)(x∈A,y∈B)的深度最大为多少。
输入描述
有多组数据(数据组数<=5)
对于每一组数据,首先2个数n,m,表示有根树的节点个数和询问个数。然后n-1行,每行2个数a,b表示节点a和节点b之间存在直接的连边;接下去2m行,每两行,分别描述当前询问的集合A和集合B;对于一个集合,用一行来描述,该行第一个数K表示集合元素的个数,后面K个数表示集合中的元素。
输出描述
一个整数,表示LCA(x,y)(x∈A,y∈B)的最大深度。
数据范围
n,m<=100000, 1<=a,b<=n, ΣK<=100000, 1<=集合中的元素<=n
题解
问最大深度,那么我们思考是否可以二分答案。
当然可以,本题的条件满足二分答案的前提,LCA基本的性质还是比较明显的。(假设a和b深度一样)设anst[x][y]为节点x往上走y步到达的祖先,对于一个k,如果anst[a][k]==anst[b][k],那么对于k'(k'>k),一定有anst[a][k']==anst[b][k'];对于一个k,如果anst[a][k]!=anst[b][k],那么对于k'(k'<k),一定有anst[a][k']!=anst[b][k'],而且LCA(a,b)=LCA(anst[a][k],anst[b][k])。
二分答案深度d完成之后,那么就剩下了编一个子程序判定的事情了。
那么如果判定呢?
已知祖先深度,那么就知道了每一个点所对应的祖先了是吧?那么,判断是否有公共祖先,其实就是判断A集合所对应的祖先集合与B集合所对应的祖先集合是否有交集——因为ΣK<=100000, 所以对于每一个集合元素找出它的某一深度的祖先这个复杂度貌似还是不够,ΣK*n应该会超(如果有人用ΣK*n的判定复杂度过了本题, 跪求留代码) 。那么我们要更快的找到这个祖先,那么是什么?倍增啊!
fa[i][j]表示与节点i深度差为2^j的i的祖先,那么不难写出转移方程:
fa[i][0]=father[i],fa[i][j]=fa[fa[i][j-1]][j-1] (father[i]表示节点i的父亲节点)
So,求某一深度的祖先就是和倍增求LCA的前一半类似的了。
至于两个集合判断交集,就是排个序,然后两个指针扫过去就可以了。
注意: 在求祖先时,要首先把那些不合法的祖先过滤掉; 在判断交集的时候,要注意边界情况!
代码
#include <cstring>
#include <cstdlib>
#include <algorithm>
#include <cstdio>
#include <cmath>
using namespace std;
const int N=,M=N*,rt=;
struct Edge{
int cnt,y[M],nxt[M],fst[N];
void set(){
cnt=;
memset(y,,sizeof y);
memset(nxt,,sizeof nxt);
memset(fst,,sizeof fst);
}
void add(int a,int b){
y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
}
}e;
int n,m,depth[N],fa[N][],ta,a[N],tb,b[N],ansta[N],anstb[N];
void build(int prev,int rt){
fa[rt][]=prev,depth[rt]=depth[prev]+;
for (int i=;(<<i)<=depth[rt];i++)
fa[rt][i]=fa[fa[rt][i-]][i-];
for (int i=e.fst[rt];i;i=e.nxt[i])
if (e.y[i]!=prev)
build(rt,e.y[i]);
}
int get_kth_anst(int p,int k){
for (int i=k,j=;i>;i>>=,j++)
if (i&)
p=fa[p][j];
return p;
}
bool check(int d){
int at=,bt=;
for (int i=;i<=ta;i++)
if (depth[a[i]]>=d)
ansta[++at]=get_kth_anst(a[i],depth[a[i]]-d);
for (int i=;i<=tb;i++)
if (depth[b[i]]>=d)
anstb[++bt]=get_kth_anst(b[i],depth[b[i]]-d);
if (at==||bt==)
return ;
int pa=,pb=;
sort(ansta+,ansta+at+);
sort(anstb+,anstb+bt+);
if (ansta[]==anstb[])
return ;
while (pa<=at&&pb<=bt){
while (pa<=at&&ansta[pa]<anstb[pb])
pa++;
if (pa>at)
break;
if (ansta[pa]==anstb[pb])
return ;
while (pb<=bt&&ansta[pa]>anstb[pb])
pb++;
if (pb>bt)
break;
if (ansta[pa]==anstb[pb])
return ;
}
return ;
}
int main(){
while (~scanf("%d%d",&n,&m)){
e.set();
for (int i=,a,b;i<n;i++)
scanf("%d%d",&a,&b),e.add(a,b),e.add(b,a);
depth[]=-;
build(,rt);
while (m--){
scanf("%d",&ta);
for (int i=;i<=ta;i++)
scanf("%d",&a[i]);
scanf("%d",&tb);
for (int i=;i<=tb;i++)
scanf("%d",&b[i]);
int le=,ri=n-,mid,ans=;
while (le<=ri){
mid=(le+ri)>>;
if (check(mid))
le=mid+,ans=mid;
else
ri=mid-;
}
printf("%d\n",ans+);
}
}
return ;
}
为了方便大家找茬,特地附上一份造数据的PASCAL代码,用于对拍。
var
t, i: longint;
function min(a, b: longint): longint;
begin
if (a > b) then
exit(b);
exit(a);
end;
procedure make_list(n ,m: longint);
var
i, j: longint;
begin
write(m, ' ');
j := ;
for i := to m do
begin
j := j + random(n - j - m + i) + ;
write(j, ' ');
end;
writeln;
end;
procedure mkdata;
const
maxn = ;
maxm = ;
add = ;
var
n, m, i, j, x, y, a, b: longint;
begin
n := random(maxn) + ;
m := random(maxm) + ;
writeln(n, ' ', m);
for i := to n do
begin
x := i;
y := random(i - ) + ;
if (random() = ) then
writeln(x, ' ', y)
else
writeln(y, ' ', x);
end;
writeln;
for i := to m do
begin
a := min(random(maxn div m + add)+, n);
b := min(random(maxn div m + add)+, n);
make_list(n, a);
make_list(n, b);
end;
writeln;
end;
begin
assign(output, 'anst.in');
rewrite(output);
randomize;
t := random() + ;
for i := to t do
mkdata;
close(output);
end.
HDU6031 Innumerable Ancestors 倍增 - 题意详细概括 - 算法详解的更多相关文章
- BM算法 Boyer-Moore高质量实现代码详解与算法详解
Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...
- 机器学习经典算法详解及Python实现--基于SMO的SVM分类器
原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector ...
- 安全体系(二)——RSA算法详解
本文主要讲述RSA算法使用的基本数学知识.秘钥的计算过程以及加密和解密的过程. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(一)—— DES算法详解 1.概述 ...
- 第三十一节,目标检测算法之 Faster R-CNN算法详解
Ren, Shaoqing, et al. “Faster R-CNN: Towards real-time object detection with region proposal network ...
- 第二十九节,目标检测算法之R-CNN算法详解
Girshick, Ross, et al. “Rich feature hierarchies for accurate object detection and semantic segmenta ...
- A*算法详解链接
A星算法详解(个人认为最详细,最通俗易懂的一个版本) Introduction to the A* Algorithm 路径规划: a star, A星算法详解 实现A星算法
- KM算法详解[转]
KM算法详解 原帖链接:http://www.cnblogs.com/zpfbuaa/p/7218607.html#_label0 阅读目录 二分图博客推荐 匈牙利算法步骤 匈牙利算法博客推荐 KM算 ...
- ST算法详解
ST算法详解 Coded by Jelly_Goat. All rights reserved. 这个主要是说ST表的. 首先了解一下ST表是什么. 先来一个老套的情景带入. (假设所有的题目都是1s ...
- [Network Architecture]DPN(Dual Path Network)算法详解(转)
https://blog.csdn.net/u014380165/article/details/75676216 论文:Dual Path Networks 论文链接:https://arxiv.o ...
随机推荐
- python学习第3天
03 int 十进制与二进制之间的转换04 bool 05 str python中凡是用引号引起来的都是字符串 1,存储相对少量的数据. 2,描述信息. 1,bool str int 三者之间的转换 ...
- push to origin/master was rejected错误解决方案
idea中,发布项目到OSChina的Git中,当时按照这样的流程添加Git,然后push,提示:push to origin/master war rejected". 解决方案如下: 1 ...
- __dict__(字典的另一种用法)
class Foo(): def __init__(self): self.name=None self.age=19 self.addr='上海' @property def dict(self): ...
- iOS 横屏模态进入下一级界面, 竖屏退出
首先 Deployment Info 设置 除了 Upside Down 都勾选 然后,在AppDelegate.h 文件中 添加属性 @property(nonatomic,assign)NSI ...
- swift 学习- 24 -- 协议 01
// 协议 定义了一个蓝图, 规定了用来实现某一特定任务或者功能的方法, 属性, 以及其他需要的东西. // 类, 结构体, 或 枚举都可以遵循协议, 并且为协议定义的这些要求 提供具体的实现, 某个 ...
- Confluence 6 配置文件和key
找到配置文件 缓存的配置文件是存储在 <confluence-home>/shared-home/config/cache-settings-overrides.properties 中的 ...
- java 得到目录路径的方法
得到web项目的根目录路径 System.getProperty("user.dir")// String path = this.getServletContext().getR ...
- 关系代数和sql语句对应关系
关系代数运算符 对应sql语句 聚合操作 ∪ (UNION)并 ∩ (INTERSECTION)交 - (DIFFERENCE)差 × (Cartesian PRODUCT)笛卡尔积 ...
- trade war
问题 C: trade war 时间限制: 1 Sec 内存限制: 128 MB 题目描述 2018年的春天,特朗普这个不靠谱的的家伙悍然向中国发起了贸易战,贸易战是一场没有赢家的战争,美国向中国商 ...
- ATM机模拟系统
实验要求 https://pan.baidu.com/s/1Sq5joWyVsNhY8DYiyI4UmQ 源代码 /*信1705-1 20173458 王嘉梁*/ package atm; impor ...