给定一棵树求任意两个节点的公共祖先

tarjan离线求LCA思想是,先把所有的查询保存起来,然后dfs一遍树的时候在判断。如果当前节点是要求的两个节点当中的一个,那么再判断另外一个是否已经访问过,如果访问过的话,那么它的最近公共祖先就是当前节点祖先。

下面是tarjan离线模板:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = ; struct Edge {
int to, next;
}edge[maxn * ];
//查询
struct Query {
int q, next;
int index;
}query[maxn * ]; int tot, head[maxn];
//查询的前向星
int cnt, h[maxn];
//查询的答案保存在ans中
int ans[maxn * ];
int fa[maxn];//并查集
int r[maxn];//并查集集合个数
int ancestor[maxn];//祖先
bool vis[maxn];//访问标记
int Q;//查询总数
void init(int n)
{
tot = ;
cnt = ;
Q = ;
memset(h, -, sizeof(h));
memset(head, -, sizeof(head));
memset(fa, -, sizeof(fa));
memset(ancestor, , sizeof(ancestor));
memset(vis, false, sizeof(vis));
for (int i = ; i <= n; i++) r[i] = ;
}
void addedge(int u, int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void addquery(int u, int v, int index)
{
query[cnt].q = v;
query[cnt].index = index;
query[cnt].next = h[u];
h[u] = cnt++;
}
int find(int x)
{
if (fa[x] == -) return x;
return fa[x] = find(fa[x]);
}
void Union(int x, int y)
{
int t1 = find(x);
int t2 = find(y);
if (t1 != t2)
{
if (t1 < t2)
{
fa[t1] = t2;
r[t2] += r[t1];
}
else
{
fa[t2] = t1;
r[t1] += r[t2];
}
}
}
void LCA(int u)//tarjan离线算法
{
vis[u] = true;
ancestor[u] = u;
for (int i = head[u]; i != -; i = edge[i].next)
{
int v = edge[i].to;
if (vis[v]) continue;
LCA(v);
Union(u, v);
ancestor[find(u)] = u;
}
for (int i = h[u]; i != -; i = query[i].next)
{
int v = query[i].q;
if (vis[v])
{
ans[query[i].index] = ancestor[find(v)];
}
}
}
bool in[maxn];
int main()
{
int T, n;
scanf("%d", &T);
while (T--)
{
scanf("%d", &n);
init(n);
memset(in, false, sizeof(in));
int u, v;
for (int i = ; i < n; i++)
{
scanf("%d %d", &u, &v);
in[v] = true;
addedge(u, v);
addedge(v, u);
}
scanf("%d %d", &u, &v);
addquery(u, v, Q);//添加查询
addquery(v, u, Q++);
int root;
for (int i = ; i <= n; i++)
{
if (!in[i])
{
root = i;
break;
}
}
LCA(root);
for (int i = ; i < Q; i++)//按照顺序打印出来答案
printf("%d\n", ans[i]);
}
return ;
}

RMQ&LCA在线模板:

RMQ st算法是用来求一段连续的区间最值问题的,如果将树看成一个线性结构,那么它可以快速求出一段区间的最值,那么就可以利用它求出LCA,首先求出一个树的欧拉序列(就是dfs序),然后每个节点都有深度,都有到根节点的距离。保存一个第一次访问到某个节点的编号。这样求两个点的LCA就是求从欧拉序列当中的一段到另外一段(连续的)深度的最小值。直接RMQ就可以了。模板如下:

#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm> using namespace std;
typedef long long ll;
const int maxn = ;
int tot, head[maxn];
struct Edge {
int to, next;
}edge[maxn];
int occur[maxn];
int first[maxn];
int dep[maxn];
bool vis[maxn];
int m;
void init()
{
tot = ;
memset(head, -, sizeof(head));
memset(vis, false, sizeof(vis));
memset(first, , sizeof(first));
m = ;
}
void addedge(int u, int v)
{
edge[tot].to = v;
edge[tot].next = head[u];
head[u] = tot++;
}
void dfs(int u, int depth)
{
occur[++m] = u;
dep[m] = depth;
if (!first[u])
first[u] = m;
for (int i = head[u]; i != -; i = edge[i].next)
{
int v = edge[i].to;
dfs(v, depth + );
occur[++m] = u;
dep[m] = depth;
}
}
int Rmin[maxn * ][];
void RMQ(int n)
{
for (int i = ; i <= n; i++)
Rmin[i][] = i;
int k = (int)log2(n);
for (int j = ; j <= k; j++)
{
for (int i = ; i + ( << j) - <= n; i++)
Rmin[i][j] = dep[Rmin[i][j - ]] < dep[Rmin[i + ( << (j - ))][j - ]] ? Rmin[i][j - ] : Rmin[i + ( << (j - ))][j - ];
}
}
int query(int a, int b)
{
int l = first[a], r = first[b];
if (l > r)
swap(l, r);
int k = (int)log2(r - l + );
int tmp = dep[Rmin[l][k]] < dep[Rmin[r - ( << k) + ][k]] ? Rmin[l][k] : Rmin[r - ( << k) + ][k];
return occur[tmp];
}
int main()
{
int T, n;
scanf("%d", &T);
while (T--)
{
init();
scanf("%d", &n);
int a, b;
for (int i = ; i < n; i++)
{
scanf("%d %d", &a, &b);
addedge(a, b);
vis[b] = true;
}
int root;
for (int i = ; i <= n; i++)
{
if (!vis[i])
{
root = i;
break;
}
}
dfs(root, );
scanf("%d %d", &a, &b);
RMQ(m);
printf("%d\n", query(a, b));
}
return ;
}

POJ 1330 Nearest 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题解

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

  3. poj 1330 Nearest Common Ancestors lca 在线rmq

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

  4. poj 1330 Nearest Common Ancestors LCA

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

  5. POJ 1330 Nearest Common Ancestors (LCA,倍增算法,在线算法)

    /* *********************************************** Author :kuangbin Created Time :2013-9-5 9:45:17 F ...

  6. POJ - 1330 Nearest Common Ancestors(基础LCA)

    POJ - 1330 Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000KB   64bit IO Format: %l ...

  7. POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA)

    POJ 1330 Nearest Common Ancestors / UVALive 2525 Nearest Common Ancestors (最近公共祖先LCA) Description A ...

  8. POJ 1330 Nearest Common Ancestors(lca)

    POJ 1330 Nearest Common Ancestors A rooted tree is a well-known data structure in computer science a ...

  9. POJ 1330 Nearest Common Ancestors 倍增算法的LCA

    POJ 1330 Nearest Common Ancestors 题意:最近公共祖先的裸题 思路:LCA和ST我们已经很熟悉了,但是这里的f[i][j]却有相似却又不同的含义.f[i][j]表示i节 ...

随机推荐

  1. PHP对象类型在内存中的分配

    对象类型和整型.字符串等类型一样,也是PHP中的一种数据类型.都是在程序中用于存储不同类型数据使用的,在程序运行时它的每部分内容都要先加载到内存中再被使用.那么对象类型的数据在内存中是如何分配的呢?先 ...

  2. PHP面向对象(OOP):__set(),__get(),__isset(),__unset()四个方法的应用

    一般来说,总是把类的属性定义为private,这更符合现实的逻辑.但是, 对属性的读取和赋值操作是非常频繁的,因此在PHP5中,预定义了两个函数”__get()”和”__set()”来获取和赋值其属性 ...

  3. Flask jQuery ajax

    http://www.runoob.com/jquery/jquery-ref-ajax.html http://jun1986.iteye.com/blog/1399242 下面是jQuery官方给 ...

  4. bzoj3637: Query on a tree VI

    Description You are given a tree (an acyclic undirected connected graph) with n nodes. The tree node ...

  5. Linux——搭建PHP开发环境第三步:mysql

    原文链接:http://www.jb51.net/article/83647.htm 1.第一步就是看linu是否安装了mysql,经过rpm -qa|grep mysql查看到centos下安装了m ...

  6. 简明解释算法中的大O符号

    伯乐在线导读:2009年1月28日Arec Barrwin在StackOverflow上提问,“有没有关于大O符号(Big O notation)的简单解释?尽量别用那么正式的定义,用尽可能简单的数学 ...

  7. Can deep learning help you find the perfect girl?

    Can deep learning help you find the perfect girl? One of the first things I did when I moved to Mont ...

  8. Linux下安装软件心得

    1 软件安装方法: 源代码编译安装:tar.gz等压缩格式,需要经过手动编译,./configure,make ,make install ,然后进行配置操作 二进制安装:tar.gz等压缩格式,解压 ...

  9. Linux Kernel 'MSR' Driver Local Privilege Escalation

    本站提供程序(方法)可能带有攻击性,仅供安全研究与教学之用,风险自负! // PoC exploit for /dev/cpu/*/msr, 32bit userland on a 64bit hos ...

  10. ♫【HTML5 敏捷实践】第1章 使用语义化的方式实现

    <!DOCTYPE html> 向后兼容的HTML5<doctype>标签.HTML5规范规定<doctype>对大小写不敏感:然而,之前版本的HTML需要< ...