HDU 5266 bc# 43 LCA+跳表
学了一发LCA的倍增算法+跳表维护。
先说说LCA倍增算法,思路是fa[i][j]求的是i结点的2^j倍的祖先,其中2^0就是父结点了。所以可以递推fa[i][j]=fa[fa[i][j-1]][j-1]。
当求LCA时,设深度u>v,则先倍增把u提到v的同等深度,若u==v,lca就是u,否则,两点同时倍增,直到最小深度的p[u][j]!=p[v][j],此时他们的父亲p[u][0]即lca。
可以看大牛http://www.cnblogs.com/OUSUO/p/3805715.html?utm_source=tuicool,先转一发。

inline void dfs(int u)
{
int i;
for(i=head[u];i!=-1;i=next[i])
{
if (!deep[to[i]])
{
deep[to[i]] = deep[u]+1;
p[to[i]][0] = u; //p[x][0]保存x的父节点为u;
dfs(to[i]);
}
}
}

2. 初始各个点的2^j祖先是谁 ,其中2^j(j=0...log(该点深度))倍祖先,1倍祖先就是父亲,2倍祖先是父亲的父亲......。

void init()
{
int i,j;
//p[i][j]表示i结点的第2^j祖先
for(j=1;(1<<j)<=n;j++)
for(i=1;i<=n;i++)
if(p[i][j-1]!=-1)
p[i][j]=p[p[i][j-1]][j-1];//i的第2^j祖先就是i的第2^(j-1)祖先的第2^(j-1)祖先
}


int lca(int a,int b)//最近公共祖先
{
int i,j;
if(deep[a]<deep[b])swap(a,b);
for(i=0;(1<<i)<=deep[a];i++);
i--;
//使a,b两点的深度相同
for(j=i;j>=0;j--)
if(deep[a]-(1<<j)>=deep[b])
a=p[a][j];
if(a==b)return a;
//倍增法,每次向上进深度2^j,找到最近公共祖先的子结点
for(j=i;j>=0;j--)
{
if(p[a][j]!=-1&&p[a][j]!=p[b][j])
{
a=p[a][j];
b=p[b][j];
}
}
return p[a][0];
}

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std; const int N=300010; struct Edge{
int v,next;
}edge[N*2];
int head[N],tot;
int fa[N][22],dp[N][22];
int dep[N]; void addedge(int u,int v){
edge[tot].v=v;
edge[tot].next=head[u];
head[u]=tot++;
} void BFS(int rt){
queue<int>que;
que.push(rt);
fa[rt][0]=-1; dep[rt]=1;
while(!que.empty()){
int u=que.front();
que.pop();
for(int i=1;i<=20;i++){
if(fa[u][i-1]!=-1){
fa[u][i]=fa[fa[u][i-1]][i-1];
}
}
for(int e=head[u];e!=-1;e=edge[e].next){
int v=edge[e].v;
if(dep[v]==0){
dep[v]=dep[u]+1;
fa[v][0]=u;
que.push(v);
}
}
}
} int LCA(int u,int v){
int i,j;
if(dep[u]<dep[v])swap(u,v);
for(i=0;(1<<i)<=dep[u];i++);
i--;
for(j=i;j>=0;j--){
if(dep[u]-(1<<j)>=dep[v])
u=fa[u][j];
}
if(u==v) return u;
for(j=i;j>=0;j--){
if(fa[u][j]!=-1&&fa[u][j]!=fa[v][j]){
u=fa[u][j];
v=fa[v][j];
}
}
return fa[u][0];
} int main(){
int n,q,u,v;
while(scanf("%d",&n)!=EOF){
memset(head,-1,sizeof(head));
tot=0;
memset(fa,-1,sizeof(fa));
for(int i=1;i<n;i++){
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
memset(dep,0,sizeof(dep));
BFS(1);
// cout<<LCA(1,5)<<endl;
// cout<<LCA(2,3)<<endl;
for(int i=1;i<=n;i++)
dp[i][0]=i;
for(int j=1;j<=20;j++){
for(int i=1;i+(1<<j)-1<=n;i++)
dp[i][j]=LCA(dp[i][j-1],dp[i+(1<<(j-1))][j-1]);
}
/* for(int i=1;i<=n;i++){
for(int j=0;j<=6;j++)
cout<<dp[i][j]<<" ";
cout<<endl;
}*/
scanf("%d",&q);
while(q--){
scanf("%d%d",&u,&v);
// if(u>v) swap(u,v);
if(u==v)
printf("%d\n",u);
else{
int ans=u;
for(int i=20;i>=0;i--){
if(u+(1<<i)-1<=v){
ans=LCA(ans,dp[u][i]);
u=u+(1<<i);
}
}
printf("%d\n",ans);
}
}
}
return 0;
}
HDU 5266 bc# 43 LCA+跳表的更多相关文章
- HDU 5266 pog loves szh III (线段树+在线LCA转RMQ)
题目地址:HDU 5266 这题用转RMQ求LCA的方法来做的很easy,仅仅须要找到l-r区间内的dfs序最大的和最小的就能够.那么用线段树或者RMQ维护一下区间最值就能够了.然后就是找dfs序最大 ...
- hdu 5266 pog loves szh III(lca + 线段树)
I - pog loves szh III Time Limit:6000MS Memory Limit:131072KB 64bit IO Format:%I64d & %I ...
- skiplist 跳表(1)
最近学习中遇到一种新的数据结构,很实用,搬过来学习. 原文地址:skiplist 跳表 为什么选择跳表 目前经常使用的平衡数据结构有:B树,红黑树,AVL树,Splay Tree, Treep等. ...
- SkipList跳表基本原理
为什么选择跳表 目前经常使用的平衡数据结构有:B树,红黑树,AVL树,Splay Tree, Treep等. 想象一下,给你一张草稿纸,一只笔,一个编辑器,你能立即实现一颗红黑树,或者AVL树 出来吗 ...
- 算法进阶面试题06——实现LFU缓存算法、计算带括号的公式、介绍和实现跳表结构
接着第四课的内容,主要讲LFU.表达式计算和跳表 第一题 上一题实现了LRU缓存算法,LFU也是一个著名的缓存算法 自行了解之后实现LFU中的set 和 get 要求:两个方法的时间复杂度都为O(1) ...
- 数据结构笔记之跳表(SkipList)
一.跳表简述 跳表可以看做是一个带有索引的链表,在介绍跳表之前先看一下一个普通的链表,假如当前维护了一个有序的链表: 现在要在这个链表中查找128,因为事先不知道链表中数值的分布情况,我们只能从前到后 ...
- C语言跳表(skiplist)实现
一.简介 跳表(skiplist)是一个非常优秀的数据结构,实现简单,插入.删除.查找的复杂度均为O(logN).LevelDB的核心数据结构是用跳表实现的,redis的sorted set数据结构也 ...
- K:跳表
跳表(SkipList)是一种随机化的数据结构,目前在redis和leveldb中都有用到它,它的效率和红黑树以及 AVL 树不相上下,但跳表的原理相当简单,只要你能熟练操作链表, 就能轻松实现一 ...
- SkipList跳表(一)基本原理
一直听说跳表这个数据结构,说要学一下的,懒癌犯了,是该治治了 为什么选择跳表 目前经常使用的平衡数据结构有:B树.红黑树,AVL树,Splay Tree(这个树好像还没有听说过),Treep(也没有听 ...
随机推荐
- C 语言程序员必读的 5 本书,你读过几本?
你正通过看书来学习C语言吗?书籍是知识的丰富来源.你可以从书中学到各种知识.书籍可以毫无歧视地向读者传达作者的本意.C语言是由 Dennis Ritchie在1969年到1973年在贝尔实验室研发的. ...
- Linux 下 Solr的搭建与使用(建议jdk1.8以上)
官方表示solr5之后的版本不再提供对第三方容器的支持(不提供war包了). “旧式”solr.xml格式不再支持,核心必须使用core.properties文件定义. 使用第三方容器的需要自己手动修 ...
- Educational Codeforces Round 45
A. 一个小模拟 不解释 //By SiriusRen #include <bits/stdc++.h> using namespace std; long long n,m,a,b ...
- Mybatis的Dao向mapper传多个参数(三种解决方案)
第一种方案 : DAO层的函数方法 Public User selectUser(String name,String area); 对应的Mapper.xml <select id=" ...
- 新认知之WinForm窗体程序
Windows应用程序和控制台应用程序有很大的区别 >Form1.cs :窗体文件,程序员对窗体编写的代码一般都存放在这个文件中. >Form1.Designer.cs :窗体设计文件, ...
- [ HNOI 2006 ] 公路修建问题
\(\\\) \(Description\) 一个\(N\)个点\(M\)条边的图,每条边可以选择\(w_i,p_i\)两个边权之一,现求一个生成树上的最大边权最小值,要求这棵生成树上至少有\(K\) ...
- TCP协议滑动窗口(一)——控制大批量数据传输速率
窗口大小:TCP头中一个16位的域,表示当前可用接受缓冲区大小.在每个TCP对等段连接初始化时,告诉对方自己的窗口大小(不一定是满额,假如满额65201字节,可能暂时通告5840字节).若客户端接受数 ...
- servlet-请求重定向
package servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.ser ...
- SQLServer bigint 转 int带符号转换函数(原创)
有一个需求是要在一个云监控的状态值中存储多个状态(包括可同时存在的各种异常.警告状态)使用了位运算机制在一个int型中存储. 现在监控日志数据量非常大(亿级别)需要对数据按每小时.每天进行聚合,供在线 ...
- log4j最全教程
(转自http://www.codeceo.com/article/log4j-usage.html) 日志是应用软件中不可缺少的部分,Apache的开源项目log4j是一个功能强大的日志组件,提供方 ...