HDU6031:Innumerable Ancestors(二分+倍增数组)
传送门
题意
n个点的图,有n-1条无向边,m个询问,每次询问
给出两个集合a和b,找到a的一个元素x,b的一个元素y,使得x和y的lca深度最大
分析
这道题如果直接暴力做,复杂度为O(mk1k2*n),爆掉
考虑二分lca的深度,那么进行如下处理,对于深度deep,如果两个集合(a存在元素x,b存在元素y),使得x向上走depth[x]-deep次与y向上走depth[y]-deep次走到的点相同,那么该深度满足条件。具体做法:
1.统计a数组中每个点向上走depth[i]-deep次到达的点,放入集合中
2.查询b数组中是否存在点向上走depth[i]-deep次到达集合中的点
有则返回true,否则返回false
代码
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<algorithm>
using namespace std;
int n,m,k1,k2,a[100100],b[100100];
vector<int>mp[100100];
#define F(i,a,b) for(int i=a;i<=b;++i)
#define mem(a,b) memset(a,b,sizeof(a))
int fa[100100],up[100100][20],depth[100100];
void dfs(int u,int pre,int deep)//遍历,标记父亲,深度
{
fa[u]=pre;
depth[u]=deep;
int num=mp[u].size();
F(i,0,num-1)if(mp[u][i]!=pre)
{
dfs(mp[u][i],u,deep+1);
}
}
void init()//构建后缀数组
{
F(i,1,n) up[i][0]=fa[i];
F(j,1,19)F(i,1,n) up[i][j]=up[up[i][j-1]][j-1];
}
int judge(int a,int deep)//返回a的deep深度的祖先
{
if(deep<0) return -1;
if(deep==0) return a;
for(int i=19;i>=0;--i) if(deep&(1<<i))
{
a=up[a][i];
}
return a;
}
int check(int deep)//判断该深度两个集合是否存在深度相同的两个点
{
set<int>s;
F(i,1,k1)//记录该深度下所有祖先
{
int ret=depth[a[i]]-deep;
int anc=judge(a[i],ret);
if(anc==-1) continue;
s.insert(anc);
}
F(i,1,k2)//在数组b中找到相同深度下是否存在相同祖先
{
int ret=depth[b[i]]-deep;
int anc=judge(b[i],ret);
if(anc==-1) continue;
if(s.count(anc)) return 1;
}
return 0;
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{
int u,v;
F(i,1,n) mp[i].clear();
F(i,1,n-1)//建图
{
scanf("%d %d",&u,&v);
mp[u].push_back(v);
mp[v].push_back(u);
}
dfs(1,0,0);
init();
F(i,1,m)
{
int l=1,r=1,ans=0;
scanf("%d",&k1);
//printf("%d\n",n);
//F(i,1,n) printf("%d%c",depth[i],i==n?'\n':' ');
F(i,1,k1) {scanf("%d",a+i);r=max(depth[a[i]],r);}
//puts("flag");
scanf("%d",&k2);
F(i,1,k2) scanf("%d",b+i);
while(l<=r)//二分深度
{
int mid=(l+r)>>1;
if(check(mid)) { ans=mid;l=mid+1; }else r=mid-1;
}
printf("%d\n",ans+1);
}
}
return 0;
}
HDU6031:Innumerable Ancestors(二分+倍增数组)的更多相关文章
- HDU-6031 Innumerable Ancestors(二分+树上倍增)
题意 给一棵树,$m$次询问,每次询问给两个点集问从两个点集中各取一个点的$LCA$的最大深度. 思路 二分答案.对于某个二分过程中得到的$Mid$,如果可行则两个点集在$Mid$所在的深度存在公共的 ...
- HDU6031 Innumerable Ancestors 倍增 - 题意详细概括 - 算法详解
去博客园看该题解 题目 查看原题 - HDU6031 Innumerable Ancestors 题目描述 有一棵有n个节点的有根树,根节点为1,其深度为1,现在有m个询问,每次询问给出两个集合A和B ...
- POJ.1330 Nearest Common Ancestors (LCA 倍增)
POJ.1330 Nearest Common Ancestors (LCA 倍增) 题意分析 给出一棵树,树上有n个点(n-1)条边,n-1个父子的边的关系a-b.接下来给出xy,求出xy的lca节 ...
- JZYZOJ1454 NOIP2015 D2T3_运输计划 二分 差分数组 lca tarjan 树链剖分
http://172.20.6.3/Problem_Show.asp?id=1454 从这道题我充分认识到我的脑子里好多水orz. 如果知道了这个要用二分和差分写,就没什么思考上的难点了(屁咧你写了一 ...
- 【bzoj2280】[Poi2011]Plot 二分+倍增+二分+最小圆覆盖
题目描述 给出一系列点p_1, p_2, ... , p_n,将其分成不多余m个连续的段,第i段内求一个点q_i,使得q_i到这段内点的距离的最大值的最大值最小 输入 第一行,n m下面n行,每行两个 ...
- 51nod 1105 第K大的数 【双重二分/二分套二分/两数组任意乘积后第K大数】
1105 第K大的数 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 收藏 关注 数组A和数组B,里面都有n个整数.数组C共有n^2个整数,分别是A[0] * ...
- 洛谷 P1083 [ NOIP 2012 ] 借教室 —— 线段树 / 二分差分数组
题目:https://www.luogu.org/problemnew/show/P1083 当初不会线段树的时候做这道题...对差分什么不太熟练,一直没A,放在那儿不管... 现在去看,线段树就直接 ...
- BZOJ 2946 [Poi2000]公共串 (二分+Hash/二分+后缀数组/后缀自动机)
求多串的最长公共字串. 法1: 二分长度+hash 传送门 法2: 二分+后缀数组 传送门 法3: 后缀自动机 拿第一个串建自动机,然后用其他串在上面匹配.每次求出SAM上每个节点的最长匹配长度后,再 ...
- LeetCode 81,在不满足二分的数组内使用二分法 II
本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是LeetCode专题第50篇文章,我们来聊聊LeetCode中的81题Search in Rotated Sorted ArrayII ...
随机推荐
- 配置 yum 源相关
1. 修改yum配置 http://www.cnblogs.com/shuaixf/archive/2011/11/30/2268496.html 2. centos安装 epel 源 https:/ ...
- BubbleGum96 开箱杂谈与软件资源
前言 原创文章,转载引用务必注明链接. 拿到有一段时间了,一直在想写哪些内容.96boards发布以来,吸引了很多眼球.这里我就慢慢随便聊聊,希望能让大家对96boards有更多了解. 开箱 [开箱图 ...
- Unity ----- 对象池GameObjectPool
孙广东 2014.6.28 非常早之前看到的外国文章,认为不错,分享一下. 对象池在AssetStore中也是有非常多插件的,可是有些重了.自己写一个轻量的岂不是非常好. 当你须要创建大量某种类型对象 ...
- C++学习总结 复习篇2
延续上一小节内容:下面继续讲解虚函数和多态 虚函数和多态 基类指针可以指向任何派生类的对象,但是不能调用派生类对象的成员. 但是,基类可以调用覆盖了虚函数的函数.(现在调用将来,这有问题,说明现在 ...
- Effective C++ 条款五 了解C++默默编写并调用哪些函数
//申明一个类时,编译器会默认为你提供四个函数. //无参构造函数,析构函数,copy构造函数,copy assignment操作符. template <typename T> ...
- TinyXML:属性
TiXmlAttribute: 代表XML中的属性,TiXmlAttribute中定义了一系列对属性的操作 TiXmlAttribute的友元类: friend class TiXmlAttribut ...
- adb的那点小事——360电视助手实现研究
欢迎转载,转载请注明:http://blog.csdn.net/zhgxhuaa 1. 前言 1.1. 行业背景简单介绍 当下,智能家居与智能穿戴设备无疑是继智能手机后两个最热门的方向.而智能家 ...
- java反射机制与动态加载类
什么是java反射机制? 1.当程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言.我们认为java并不是动态语言,但是它却有一个非常突出的动态相关机制,俗称:反射. IT行业里这么说,没有 ...
- (linux)wake_lock机制
Android的休眠唤醒主要基于wake_lock机制,只要系统中存在任一有效的wake_lock,系统就不能进入深度休眠,但可以进行设备的浅度休眠操作.wake_lock一般在关闭lcd.tp但 ...
- !important的用法(IE6 兼容的解决方法)
我们知道,CSS写在不同的地方有不同的优先级, .css文件中的定义 < 元素style中的属性,但是如果使用!important,事情就会变得不一样. 首先,先看下面一段代码: <!DO ...