首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 其他相关 >

poj1330Nearest Common Ancestors(LCA总结)

2013-09-28 
poj1330Nearest Common Ancestors(LCA小结)题目请戳这里题目大意:意如其名。题目分析:本题只有一个查询,所

poj1330Nearest Common Ancestors(LCA小结)

题目请戳这里

题目大意:意如其名。

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

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

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

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

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

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

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

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

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

#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;}


热点排行