题目请戳这里

题目大意:意如其名。

题目分析:本题只有一个查询,所以可以各种乱搞过去。

不过对于菜鸟而言,还是老老实实练习一下LCA算法。

LCA有很多经典的算法。按工作方式分在线和离线2种。

tarjan算法是经典的离线算法。这篇博客讲的太好懂了,我也不好意思班门弄斧,具体戳进去看看就会明白。重点是那个插图,一看秒懂。

在线算法主要有倍增算法和转RMQ算法。

另外LCA还有2种更为高效的O(n)-O(1)算法。一种请戳这里,另一种其实就是先将LCA转化成RMQ,再利用笛卡尔树O(n)预处理,O(1)回答,具体可以戳这里

后两种O(n)算法还没有仔细研究,大致看了下,不是很明白,但是感觉很厉害的样子。mark一下,以后抽时间学习一下。

下面给出本题的前3种算法具体实现:

1:tarjan算法(虽然对本题来说有点奢侈了。。)

#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 10005;
struct node
{
int to,next;
}e[N];
int head[N],set[N],fa[N],in[N];
bool vis[N];
int n,num,p,q;
void build(int s,int ed)
{
e[num].to = ed;
e[num].next = head[s];
head[s] = num ++;
}
void init()
{
num = 0;
memset(head,-1,sizeof(head));
memset(in,0,sizeof(in));
}
int find(int x)
{
int rt = x;
while(set[rt] != rt)
rt = set[rt];
int pa = set[x];
while(pa != rt)
{
set[x] = rt;
x = pa;
pa = set[x];
}
return rt;
}
void bing(int a,int b)
{
int ra = find(a);
int rb = find(b);
if(ra != rb)
set[rb] = ra;
}
void dfs(int cur)
{
fa[cur] = cur;
set[cur] = cur;
int i;
for(i = head[cur];i != -1;i = e[i].next)
{
dfs(e[i].to);
bing(cur,e[i].to);
fa[find(cur)] = cur;
}
vis[cur] = true;
if((p == cur && vis[q]))
printf("%d\n",fa[find(q)]);
if((q == cur && vis[p]))
printf("%d\n",fa[find(p)]);
}
void tarjan()
{
int i;
memset(vis,false,sizeof(vis));
for(i = 1;i <= n;i ++)
if(in[i] == 0)
break;
dfs(i);
}
int main()
{
int t;
int i,a,b;
scanf("%d",&t);
while(t --)
{
scanf("%d",&n);
init();
for(i = 1;i < n;i ++)
{
scanf("%d%d",&a,&b);
build(a,b);
in[b] ++;
}
scanf("%d%d",&p,&q);
tarjan();
}
return 0;
}

2:LCA转RMQ,再st算法:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N = 20005; int dep[N],pos[N],seq[N],first[N],in[N];
int dp[N][20];
struct node
{
int to,next;
}e[N];
int head[N];
int n,num,p,q,id;
void build(int s,int ed)
{
e[num].to = ed;
e[num].next = head[s];
head[s] = num ++;
} void dfs(int cur,int deep)
{
dep[cur] = deep;
first[cur] = id;
pos[id] = cur;
seq[id ++] = dep[cur];
int i;
for(i = head[cur];i != -1;i = e[i].next)
{
dfs(e[i].to,deep + 1);
pos[id] = cur;
seq[id ++] = dep[cur];
}
}
int rmq()
{
int i,j;
for(i = 1;i <= id;i ++)
dp[i][0] = i;
for(j = 1;(1<<j) <= id;j ++)
{
for(i = 1;(i + (1<<(j - 1))) <= id;i ++)
if(seq[dp[i][j - 1]] < seq[dp[i + (1<<(j - 1))][j - 1]])
dp[i][j] = dp[i][j - 1];
else
dp[i][j] = dp[i + (1<<(j - 1))][j - 1];
}
int tp = first[p];
int tq = first[q];
if(tp > tq)
swap(tp,tq);
int k = floor(log((double)(tq - tp + 1))/log(2.0));
int tmp;
if(seq[dp[tp][k]] < seq[dp[tq - (1<<k) + 1][k]])
tmp = dp[tp][k];
else
tmp = dp[tq - (1<<k) + 1][k];
return pos[tmp];
}
void solve()
{
int i;
id = 1;
for(i = 1;i <= n;i ++)
if(in[i] == 0)
break;
dfs(i,0);
id --;
printf("%d\n",rmq());
}
int main()
{
int i,a,b,t;
freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t --)
{
scanf("%d",&n);
num = 0;
memset(head,-1,sizeof(head));
memset(in,0,sizeof(in));
for(i = 1;i < n;i ++)
{
scanf("%d%d",&a,&b);
build(a,b);
in[b] ++;
}
scanf("%d%d",&p,&q);
solve();
}
return 0;
}

3:倍增算法:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 10005; int dp[N][20],deep[N];
struct node
{
int to,next;
}e[N];
int n,num,p,q;
int head[N],in[N];
void build(int s,int ed)
{
e[num].to = ed;
e[num].next = head[s];
head[s] = num ++;
}
void dfs(int cur,int fa)
{
deep[cur] = deep[fa] + 1;
dp[cur][0] = fa;
int i;
for(i = 1;i < 18;i ++)
dp[cur][i] = dp[dp[cur][i - 1]][i - 1];
for(i = head[cur];i != -1;i = e[i].next)
{
dfs(e[i].to,cur);
}
}
int lca()
{
if(deep[p] < deep[q])
swap(p,q);
int i,j;
for(j = deep[p] - deep[q],i = 0;j;j >>= 1,i ++)
{
if(j&1)
p = dp[p][i];
}
if(p == q)
return q;
for(i = 18;i >= 0;i --)
{
if(dp[p][i] != dp[q][i])
{
p = dp[p][i];
q = dp[q][i];
}
}
return dp[q][0];
}
void solve()
{
int i;
memset(deep,0,sizeof(deep));
for(i = 1;i <= n;i ++)
if(in[i] == 0)
break;
dfs(i,0);
printf("%d\n",lca());
}
int main()
{
int t,i,a,b;
freopen("in.txt","r",stdin);
scanf("%d",&t);
while(t --)
{
scanf("%d",&n);
num = 0;
memset(head,-1,sizeof(head));
memset(in,0,sizeof(in));
for(i = 1;i < n;i ++)
{
scanf("%d%d",&a,&b);
build(a,b);
in[b] ++;
}
scanf("%d%d",&p,&q);
solve();
}
return 0;
}

poj1330Nearest Common Ancestors(LCA小结)的更多相关文章

  1. POJ.1330 Nearest Common Ancestors (LCA 倍增)

    POJ.1330 Nearest Common Ancestors (LCA 倍增) 题意分析 给出一棵树,树上有n个点(n-1)条边,n-1个父子的边的关系a-b.接下来给出xy,求出xy的lca节 ...

  2. poj 1330 Nearest Common Ancestors LCA

    题目链接:http://poj.org/problem?id=1330 A rooted tree is a well-known data structure in computer science ...

  3. POJ 1330 Nearest Common Ancestors LCA题解

    Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 19728   Accept ...

  4. pku 1330 Nearest Common Ancestors LCA离线

    pku 1330 Nearest Common Ancestors 题目链接: http://poj.org/problem?id=1330 题目大意: 给定一棵树的边关系,注意是有向边,因为这个WA ...

  5. poj 1330 Nearest Common Ancestors lca 在线rmq

    Nearest Common Ancestors Description A rooted tree is a well-known data structure in computer scienc ...

  6. Nearest Common Ancestors(LCA)

    Description A rooted tree is a well-known data structure in computer science and engineering. An exa ...

  7. poj1330Nearest Common Ancestors 1470 Closest Common Ancestors(LCA算法)

    LCA思想:http://www.cnblogs.com/hujunzheng/p/3945885.html 在求解最近公共祖先为问题上,用到的是Tarjan的思想,从根结点开始形成一棵深搜树,非常好 ...

  8. poj----1330Nearest Common Ancestors(简单LCA)

    题目连接  http://poj.org/problem?id=1330 就是构建一棵树,然后问你两个节点之间最近的公共父节点是谁? 代码: /*Source Code Problem: 1330 U ...

  9. POJ-1330--Nearest Common Ancestors(离线LCA)

    LCA离线算法 它需要一次输入所有的询问,然后有根节点开始进行深度优先遍历(DFS),在深度优先遍历的过程中,进行并查集的操作,同时查询询问,返回结果. 题意: 求A ,B两点的最近公共祖先 分析: ...

随机推荐

  1. Cuts the cake_hdu_2134.java

    Cuts the cake Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) To ...

  2. HDU ACM 1078 FatMouse and Cheese 记忆化+DFS

    题意:FatMouse在一个N*N方格上找吃的,每一个点(x,y)有一些吃的,FatMouse从(0,0)的出发去找吃的.每次最多走k步,他走过的位置能够吃掉吃的.保证吃的数量在0-100.规定他仅仅 ...

  3. [Cycle.js] The Cycle.js principle: separating logic from effects

    The guiding principle in Cycle.js is we want to separate logic from effects. This first part here wa ...

  4. C++类的继承实例

    首先由三个类分别为DateType(日期类).TimeType(时间类).DateTimeType(日期时间内).详细代码例如以下: #include <iostream> using n ...

  5. TTB 基本

    中文名 ,线程构建模块 外文名 Thread Building Blocks 缩    写 TBB 开    发 intel 目录 1线程构建模块 2黑体亮温 3斜交载重轮胎 4串联球轴承     1 ...

  6. UIApplication的作用

    1.设置app图标右上角的数字2.设置状态栏的属性(样式.是否要显示)3.打开某个链接\发短信\打电话4.keyWindow : 访问程序的主窗口(一个程序只能有一个主窗口)5.windows : 访 ...

  7. HTML页面之间跳转与传值(JS代码)

    跳转的方法如下: 方法一: window.location.href = "b.html"; 方法二(返回上一个页面,这个应该不算,先放在这): window.history.ba ...

  8. 软件工程师所需掌握的“终极技术”是什么?

    软件工程师所需掌握的"终极技术"是什么? http://yunli.blog.51cto.com/831344/1019990 最近,我在微博上看到@程序员邹欣老师发的一条微博 - ...

  9. 《第一行代码》学习笔记19-广播接收器Broadcast_Receiver(2)

    1.解决广播的安全性问题,Android引入了一套本地广播机制,使用该机制发出的广播只能够在应用程序内部进行传递,并且广播接收器只能 接收来自本应用程序发出的广播. 2.本地广播无法通过静态注册来接收 ...

  10. rsync+inotify实时同步方案

    rsync+inotify实时同步,inotify可以实时监控本地文件或目录变化,当检测到本地文件变化,执行rsync同步命令,将变化的文件同步到其他服务器节点. 1.配置环境 3.在服务节点1.服务 ...