去博客园看该题解

题目

查看原题 - 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 倍增 - 题意详细概括 - 算法详解的更多相关文章

  1. BM算法  Boyer-Moore高质量实现代码详解与算法详解

    Boyer-Moore高质量实现代码详解与算法详解 鉴于我见到对算法本身分析非常透彻的文章以及实现的非常精巧的文章,所以就转载了,本文的贡献在于将两者结合起来,方便大家了解代码实现! 算法详解转自:h ...

  2. 机器学习经典算法详解及Python实现--基于SMO的SVM分类器

    原文:http://blog.csdn.net/suipingsp/article/details/41645779 支持向量机基本上是最好的有监督学习算法,因其英文名为support vector  ...

  3. 安全体系(二)——RSA算法详解

    本文主要讲述RSA算法使用的基本数学知识.秘钥的计算过程以及加密和解密的过程. 安全体系(零)—— 加解密算法.消息摘要.消息认证技术.数字签名与公钥证书 安全体系(一)—— DES算法详解 1.概述 ...

  4. 第三十一节,目标检测算法之 Faster R-CNN算法详解

    Ren, Shaoqing, et al. “Faster R-CNN: Towards real-time object detection with region proposal network ...

  5. 第二十九节,目标检测算法之R-CNN算法详解

    Girshick, Ross, et al. “Rich feature hierarchies for accurate object detection and semantic segmenta ...

  6. A*算法详解链接

    A星算法详解(个人认为最详细,最通俗易懂的一个版本) Introduction to the A* Algorithm 路径规划: a star, A星算法详解 实现A星算法

  7. KM算法详解[转]

    KM算法详解 原帖链接:http://www.cnblogs.com/zpfbuaa/p/7218607.html#_label0 阅读目录 二分图博客推荐 匈牙利算法步骤 匈牙利算法博客推荐 KM算 ...

  8. ST算法详解

    ST算法详解 Coded by Jelly_Goat. All rights reserved. 这个主要是说ST表的. 首先了解一下ST表是什么. 先来一个老套的情景带入. (假设所有的题目都是1s ...

  9. [Network Architecture]DPN(Dual Path Network)算法详解(转)

    https://blog.csdn.net/u014380165/article/details/75676216 论文:Dual Path Networks 论文链接:https://arxiv.o ...

随机推荐

  1. oracle 11.2.0.4 rac 打补丁

    本次安装pus环境是11.2.0.4 rac,打的patch为11.2.0.4.180717 (Includes Database PSU),gi补丁和数据库补丁一起打 安装最新opatch版本 un ...

  2. C/C++中如何在main()函数之前执行一条语句?

    在C语言中,如果使用GCC的话,可以通过attribute关键字声明constructor和destructor(C语言中如何在main函数开始前执行函数) #include <stdio.h& ...

  3. Android设备管理器——DevicePolicyManager

    自从安卓2.2(API=8)以后,安卓手机是通过设备管理API对手机进行系统级的设备管理. 本篇通过大家熟悉的"一键锁屏"的小项目实现来介绍设备管理API如何通过强制设备管理策略创 ...

  4. 51nod--1265 四点共面 (计算几何基础, 点积, 叉积)

    题目: 1265 四点共面 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题 收藏 关注 给出三维空间上的四个点(点与点的位置均不相同),判断这4个点是否在同一个平面内(4 ...

  5. [PHP]PDO各方法在发生MYSQL断开时的反应

    1.mixed PDO::errorCode ( void ) 如果单独执行此语句,并不能判断此时MYSQL是否已断开,它返回最上一次对MYSQL操作的错误码 2.public array PDO:: ...

  6. Android Apk 瘦身大法

    原文地址: https://mp.weixin.qq.com/s/XS0tuLgTfyp4rW4h69wyQQ 一, 我们在多人开发项目 或者 遗留项目中开发时,会有些自己没用到的资源文件,但是自己也 ...

  7. FTRL优化算法

    飞机票 FTRL

  8. Socket通讯成功案例

    Socket通讯案例 #region 服务端 //int port = 1234; //string host = "127.0.0.1"; //IPAddress ip = IP ...

  9. Oracle 所有的权限列表

  10. bat如何实现自动创建文件夹(以当前时间命名)

    先比较直接的查看当前的日期和时间:(或者cmd中直接输入date,time查看) @echo off color 0a set dt=%date%%time% echo %dt% pause 1.使用 ...