POJ 1330 Nearest Common Ancestors(LCA)

来源:互联网 发布:初中全程辅导软件下载 编辑:程序博客网 时间:2024/05/28 23:21

POJ 1330 Nearest Common Ancestors(LCA)

tags : acm


树链剖分搞不来,写道LCA压压惊.由于Tarjin没怎么看懂,所以就直接用dfs+st搞

题意:

给定一颗树,求两个节点的最近公共祖先

解析:

标准的LCA问题,关于LCA的做法可以参考这里

代码:

#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#include <algorithm>#include <vector>using namespace std;#define MAXN    12000int T,N;vector<int> cnn[MAXN];int pos[MAXN];      //pos数组在确定根节点时用于记录入度,在dfs时用于记录节点在路径中第一次出现的位置int d[MAXN*2][100]; //st算法中需要用到的数组vector<int> path;   //用于记录路径vector<int> depth;  //路径对应的深度void dfs(int u,int d){    int sz=cnn[u].size();    for (int i=0;i<sz;i++)    {        int v=cnn[u][i];        if (pos[v]==-1) //找到连接未访问过的点的边        {            //记录这条边远离根的端点            pos[v]=path.size();            path.push_back(v);            depth.push_back(d);            //访问下一层            dfs(v,d+1);            //记录这条边靠近根的端点            path.push_back(u);            depth.push_back(d);        }    }}void RMQ_init(const vector<int> A){    int n=A.size();    for (int i=0;i<n;i++)   d[i][0]=A[i];    for (int j=1;(1<<j)<=n;j++)        for (int i=0;i+(1<<j)-1<n;i++)            d[i][j] = min(d[i][j-1],d[i+(1<<(j-1))][j-1]);}int RMQ(int L,int R){    int k=0;    while ((1<<k+1) <= R-L+1)   k++;    return min(d[L][k],d[R-(1<<k)+1][k]);}int main(){    scanf("%d",&T);    while (T--)    {        memset(pos,0,sizeof (pos));        int u,v;        scanf("%d",&N);        for (int i=0;i<=N;i++)            cnn[i].clear();        for (int i=0;i<N-1;i++)        {            scanf("%d%d",&u,&v);            cnn[u].push_back(v);            cnn[v].push_back(u);            pos[v]++;//记录入度        }        scanf("%d%d",&u,&v);        //需要先确定根节点的标号,入度为0的点即为根节点        int root=0;        for (int i=1;i<=N;i++)            if (!pos[i])            {                root = i;                break;            }        //初始化标记数组,路径数组以及路径对应的深度数组        memset(pos,-1,sizeof (pos));        path.clear();        depth.clear();        //标记根节点        pos[root]=path.size();        path.push_back(root);        depth.push_back(1);        //进行dfs遍历,记录任意两节点之间的一条可行路径,这条路径经过该两点的最近公共祖先,且该祖先在这条路径中深度最小        dfs(root,1);        //初始化        RMQ_init(depth);        if (pos[u]>pos[v])        {            int tmp=u;            u=v;            v=tmp;        }        //获得LCA对应的深度        int min_d=RMQ(pos[u],pos[v]);        //在[pos[u],pos[v]]范围内找到深度为min_d的点(这样的点只有一个),即为LCA        for (int i=pos[u];i<=pos[v];i++)        {            if (depth[i]==min_d)            {                printf("%d\n",path[i]);                break;            }        }    }    return 0;}
0 0