lca 在线,离线 poj 1330

题目链接:Nearest Common Ancestors

在线做法:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <cmath>
using namespace std;
const int maxn=10000+10;
const int M=20;
struct node
{
    int v,next;
}e[maxn];
int bit[M];
int dp[maxn<<1][M],depth[maxn<<1],euler[maxn<<1],pos[maxn],head[maxn],vis[maxn],flag[maxn];
int T,n,tot;
void Swap(int &a,int &b)
{
    int c;
    c=a;
    a=b;
    b=c;
}
void build(int u,int v)
{
    e[T].v=v;
    e[T].next=head[u];
    head[u]=T++;
}
void init()
{
    memset(vis,0,sizeof(vis));
    memset(head,-1,sizeof(head));
    memset(flag,0,sizeof(flag));
    T=0;
    tot=0;
    int u,v;
    for(int i=0;i<n-1;i++)
    {
        scanf("%d%d",&u,&v);
        build(u,v);
        flag[v]=1;
    }
}
void dfs(int u,int dep)
{
    vis[u]=1;
    euler[++tot]=u;
    depth[tot]=dep;
    pos[u]=tot;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].v;
        if(!vis[v])
        {
            dfs(v,dep+1);
            euler[++tot]=u;
            depth[tot]=dep;
        }
    }
}
void ST(int len)
{
    for(int i=1;i<=len;i++)
        dp[i][0]=i;
    int k=(int )(log(len*1.0)/log(2.0));
    for(int j=1;j<=k;j++)
    {
        for(int i=1;i+bit[j]<=len;i++)
        {
            int l=dp[i][j-1];
            int r=dp[i+bit[j-1]][j-1];
            dp[i][j]=depth[l]<depth[r]?l:r;
        }
    }
}
int  RMQ(int x,int y)
{
    int len=y-x+1;
    int k=(int )(log(len*1.0)/log(2.0));
    int l=dp[x][k];
    int r=dp[y-bit[k]+1][k];
    return depth[l]<depth[r]?l:r;
}
void lca(int x,int y)
{
    int l=pos[x];
    int r=pos[y];
    if(l>r)
        Swap(l,r);
    printf("%d\n",euler[RMQ(l,r)]);
    return;
}
int main()
{
    //freopen("in.txt","r",stdin);
    for(int i=0;i<M;i++)
        bit[i]=1<<i;
    int kase;
    scanf("%d",&kase);
    while(kase--)
    {
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++)
        {
            if(!flag[i])
            {
                dfs(i,1);
                break;
            }
        }
        ST(2*n-1);
        int ql,qr;
        scanf("%d%d",&ql,&qr);
        lca(ql,qr);
    }
    return 0;
}

离线做法:

#include <iostream>
#include <cstdio>
#include <cstring>
#include  <algorithm>
#include <stack>
#include <queue>
#include <vector>

using namespace std;
const int maxn=10000+10;
struct node
{
    int v,next;
}e[maxn<<1];
int head[maxn],vis[maxn],fa[maxn],flag[maxn];
int T,n;
int ql,qr,q;
void build(int u,int v)
{
    e[T].v=v;
    e[T].next=head[u];
    head[u]=T++;
}
void init()
{
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof(vis));
    for(int i=1;i<=n;i++)
        fa[i]=i;
    memset(flag,0,sizeof(flag));
    T=0;
    q=0;
    int u,v;
    for(int i=0;i<n-1;i++)
    {
        scanf("%d%d",&u,&v);
        build(u,v);
        flag[v]=1;
        //build(v,u);
    }
    scanf("%d%d",&ql,&qr);
}
int  getf(int x)
{
    while(x!=fa[x])
    {
        fa[x]=getf(fa[x]);
        x=fa[x];
    }
    return x;
}
void dfs(int u)
{
    vis[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].v;
        if(!vis[v])
        {
            dfs(v);
            fa[v]=u;
        }
    }
    if(q==1)
        return;
    if(u==qr&&vis[ql])
    {
        q=1;
        printf("%d\n",getf(ql));
        return ;
    }
    if(u==ql&&vis[qr])
    {
        q=1;
        printf("%d\n",getf(qr));
        return ;
    }
}
int main()
{
    //freopen("in.txt","r",stdin);
    int kase;
    scanf("%d",&kase);
    while(kase--)
    {
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++)
        {
            if(!flag[i])
            {
                dfs(i);
                break;
            }
        }
    }
    return 0;
}
时间: 2024-10-12 00:31:48

lca 在线,离线 poj 1330的相关文章

(LCA倍增) poj 1330

Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 20260   Accepted: 10683 Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:  In the figure, eac

POJ 1330 Nearest Common Ancestors LCA(在线RMQ,离线Tarjan)

链接:http://poj.org/problem?id=1330 题意:只看题目就知道题目是什么意思了,最近公共祖先,求在一棵树上两个节点的最近公共祖先. 思路:求最近公共祖先有两种算法,在线和离线,在线方法是用RMQ求LCA,一句话总结就是在从DFS时,从第一个点到第二个点的最短路径中深度最浅的点就是公共祖先,用RMQ处理,一般问题的最优解决方式的复杂度是O(NlogN)的预处理+N*O(1)的查询.离线方法是Tarjan算法,将所有询问的两个点都记录下来,在DFS过程中不断将每个点自身作为

POJ 1330 Nearest Common Ancestors (在线LCA转RMQ)

题目地址:POJ 1330 在线LCA转RMQ第一发.所谓在线LCA,就是先DFS一次,求出遍历路径和各个点深度,那么求最近公共祖先的时候就可以转化成求从u到v经过的点中深度最小的那个. 纯模板题. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h&g

POJ 1330 LCA最近公共祖先 离线tarjan算法

题意要求一棵树上,两个点的最近公共祖先 即LCA 现学了一下LCA-Tarjan算法,还挺好理解的,这是个离线的算法,先把询问存贮起来,在一遍dfs过程中,找到了对应的询问点,即可输出 原理用了并查集和dfs染色,先dfs到底层开始往上回溯,边并查集合并 一边染色,这样只要询问的两个点均被染色了,就可以输出当前并查集的最高父亲一定是LCA,因为我是从底层层层往上DSU和染色的,要么没被染色,被染色之后,肯定就是当前节点是最近的 #include <iostream> #include <

POJ 1330 Nearest Common Ancestors 倍增算法的LCA

POJ 1330 Nearest Common Ancestors 题意:最近公共祖先的裸题 思路:LCA和ST我们已经很熟悉了,但是这里的f[i][j]却有相似却又不同的含义.f[i][j]表示i节点的第2j个父亲是多少   这个代码不是我的,转自 邝斌博客 1 /* *********************************************** 2 Author :kuangbin 3 Created Time :2013-9-5 9:45:17 4 File Name :F

POJ 1330 Nearest Common Ancestors LCA题解

本题是一个多叉树,然后求两点的最近公共单亲节点. 就是典型的LCA问题.这是一个很多解法的,而且被研究的很透彻的问题. 原始的解法:从根节点往下搜索,若果搜索到两个节点分别在一个节点的两边,那么这个点就是最近公共单亲节点了. Trajan离线算法:首次找到两个节点的时候,如果记录了他们的最低单亲节点,那么答案就是这个最低的单亲节点了. 问题是如何有效记录这个最低单亲节点,并有效根据遍历的情况更新,这就是利用Union Find(并查集)记录已经找到的节点,并及时更新最新访问的节点的当前最低单亲节

LCA 算法学习 (最近公共祖先)poj 1330

poj1330 在求解最近公共祖先为问题上,用到的是Tarjan的思想,从根结点开始形成一棵深搜树,处理技巧就是在回溯到结点u的时候,u的子树已经遍历,这时候才把u结点放入合并集合中,这样u结点和所有u的子树中的结点的最近公共祖先就是u了,u和还未遍历的所有u的兄弟结点及子树中的最近公共祖先就是u的父亲结点.这样我们在对树深度遍历的时候就很自然的将树中的结点分成若干的集合,两个集合中的所属不同集合的任意一对顶点的公共祖先都是相同的,也就是说这两个集合的最近公共祖先只有一个.时间复杂度为O(n+q

POJ 1330 裸的LCA

Nearest Common Ancestors Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 17720   Accepted: 9393 Description A rooted tree is a well-known data structure in computer science and engineering. An example is shown below:  In the figure, each

POJ 1330 Nearest Common Ancestors(LCA模板)

给定一棵树求任意两个节点的公共祖先 tarjan离线求LCA思想是,先把所有的查询保存起来,然后dfs一遍树的时候在判断.如果当前节点是要求的两个节点当中的一个,那么再判断另外一个是否已经访问过,如果访问过的话,那么它的最近公共祖先就是当前节点祖先. 下面是tarjan离线模板: #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn =