POJ-1330 Nearest Common Ancestors【LCA】

来源:互联网 发布:php音乐网站 编辑:程序博客网 时间:2024/04/29 20:36

题目链接:http://poj.org/problem?id=1330

题目大意:

给你一个树,问任意节点的最近公共祖先。

解题思路:

LCA问题。用RMQ解决。~。~不过我的办法比较2,因为我需要另外找根,另外找level数组也需要遍历。应该可以优化。


代码如下:

#include<iostream>#include<cstring>#include<cstdio>#include<algorithm>#include<vector>#include<cmath>using namespace std;#define N 10010#define M 20010int visit[M], level[M], first[N]; //深搜步骤、层、首次出现int dp[20][N]; //RMQ-dp处理vector<int>son[N]; //记录孩子int in[N]; //入度int top;int res[N]; //结果void DFS(int ceng, int now){if(first[now] == -1)first[now] = top;level[top] = ceng;visit[top++] = now;if(son[now].size() == 0) //终止条件return ;for(int i = 0; i < son[now].size(); ++i){DFS(ceng + 1, son[now][i]);level[top] = ceng;visit[top++] = now;}}void RMQ(int n) //预处理{for(int i = 1; i <= n; ++i)dp[0][i] = level[i];for(int i = 1; (1 << i) <= n; ++i)for(int j = 1; j <= n + 1 - (1 << i); ++j)dp[i][j] = min(dp[i - 1][j], dp[i - 1][j + (1 << i >> 1)]);}int ac(int start, int end) //返回最近公共祖先{int k = (int)(log((double)(end - start + 1.0)) / log(2.0));int temp = min(dp[ k ][ start ], dp[ k ][ end - (1 << k) + 1 ]);for(int i = start; i <= end; ++i) //找下标if(level[i] == temp)return visit[i];}void init(int n){top = 1;memset(in, 0, sizeof(in));memset(first, -1, sizeof(first));memset(res, 0, sizeof(res));for(int i = 1; i <= n; ++i)son[i].clear();}int main(){int ncase;int vnum;int a, b;int root;int query, start, end;scanf("%d", &ncase);while(ncase--){scanf("%d", &vnum);init(vnum); //初始化for(int i = 1; i < vnum; ++i) //读入图{scanf("%d %d", &a, &b);son[a].push_back(b);in[b]++; //入度+1}for(root = 1; in[root]; ++root); //找根DFS(0, root); //深搜RMQ(2 * vnum - 1); //O(nlogn)预处理scanf("%d %d", &start, &end);start = first[start], end = first[end]; //找到在level中的位置if(start > end) //保证前小后大swap(start, end);printf("%d\n", ac(start, end));}return 0;}


原创粉丝点击