poj1330 Nearest Common Ancestors(lca,tarjan&倍增)
2017-07-04 16:06
381 查看
Nearest Common Ancestors
DescriptionA rooted tree is a well-known data structure in computer science and engineering. An example is shown below:
In the figure, each node is labeled with an integer from {1, 2,…,16}. Node 8 is the root of the tree. Node x is an ancestor of node y if node x is in the path between the root and node y. For example, node 4 is an ancestor of node 16. Node 10 is also an ancestor of node 16. As a matter of fact, nodes 8, 4, 10, and 16 are the ancestors of node 16. Remember that a node is an ancestor of itself. Nodes 8, 4, 6, and 7 are the ancestors of node 7. A node x is called a common ancestor of two different nodes y and z if node x is an ancestor of node y and an ancestor of node z. Thus, nodes 8 and 4 are the common ancestors of nodes 16 and 7. A node x is called the nearest common ancestor of nodes y and z if x is a common ancestor of y and z and nearest to y and z among their common ancestors. Hence, the nearest common ancestor of nodes 16 and 7 is node 4. Node 4 is nearer to nodes 16 and 7 than node 8 is.
For other examples, the nearest common ancestor of nodes 2 and 3 is node 10, the nearest common ancestor of nodes 6 and 13 is node 8, and the nearest common ancestor of nodes 4 and 12 is node 4. In the last example, if y is an ancestor of z, then the nearest common ancestor of y and z is y.
Write a program that finds the nearest common ancestor of two distinct nodes in a tree.
Input
The input consists of T test cases. The number of test cases (T) is given in the first line of the input file. Each test case starts with a line containing an integer N , the number of nodes in a tree, 2<=N<=10,000. The nodes are labeled with integers 1, 2,…, N. Each of the next N -1 lines contains a pair of integers that represent an edge –the first integer is the parent node of the second integer. Note that a tree with N nodes has exactly N - 1 edges. The last line of each test case contains two distinct integers whose nearest common ancestor is to be computed.
Output
Print exactly one line for each test case. The line should contain the integer that is the nearest common ancestor.
tarjan
分析:离线lca据说不常用。代码
#include <cstdio> #include <cstring> using namespace std; struct edge { int x,y,nxt; }a[20000]; int f[20000],ls[20000],n,t,p,q,root; bool v[20000]; int init() { memset(ls,0,sizeof(ls)); memset(v,false,sizeof(v)); scanf("%d",&n); for (int i=1;i<=n;i++) { f[i]=i; a[i].nxt=0; } for (int i=1;i<n;i++) { scanf("%d%d",&a[i].x,&a[i].y); a[i].nxt=ls[a[i].x]; ls[a[i].x]=i; v[a[i].y]=true; } scanf("%d%d",&p,&q); for (int i=1;i<=n;i++) if (!v[i]) { root=i; break; } memset(v,false,sizeof(v)); return 0; } int find(int x) { if (f[x]==x) return x; f[x]=find(f[x]); return f[x]; } void dfs(int x) { v[x]=true; if ((x==p&&v[q])||(x==q&&v[p])) { if (x==p) printf("%d\n",find(q)); else printf("%d\n",find(p)); } for (int i=ls[x];i;i=a[i].nxt) { dfs(a[i].y); f[find(a[i].y)]=x; } } int main() { scanf("%d",&t); for (int i=1;i<=t;i++) { init(); dfs(root); } }
倍增
分析:用f[i,j]表示节点i的第2^j个祖先是谁。举个例子,f[i,0]就表示节点i的父亲,f[i,1]就表示节点i的爷爷。很容易想到递推式f[i,j]=f[f[i,j-1],j-1]
那么f数组就可以在O(nlogn)的时间内预处理出来。
在求两个节点x和y的lca时,假设x的深度大于等于y,那么先把x倍增到与y的深度相同的祖先,然后把x和y一起向上倍增。
代码
#include <cstdio> #include <cstring> using namespace std; struct edge { int x,y,nxt; }a[20000]; int dep[20000],f[20000][30],ls[20000]; bool v[20000]; int n,t,ans; void dfs(int d,int i) { dep[i]=d; for (int j=ls[i];j;j=a[j].nxt) dfs(d+1,a[j].y); } int lca(int p,int q) { if (dep[p]<dep[q]) { p^=q;q^=p;p^=q; } for (int i=16;i>=0;i--) if (dep[q]<=dep[f[p][i]]) p=f[p][i]; if (p==q) return p; for (int i=16;i>=0;i--) if (f[p][i]!=f[q][i]) { p=f[p][i]; q=f[q][i]; } return f[p][0]; } int main() { scanf("%d",&t); for (int l=1;l<=t;l++) { memset(ls,0,sizeof(ls)); memset(v,false,sizeof(v)); memset(f,0,sizeof(f)); memset(dep,0,sizeof(dep)); scanf("%d",&n); for (int i=1;i<n;i++) { scanf("%d%d",&a[i].x,&a[i].y); a[i].nxt=ls[a[i].x]; ls[a[i].x]=i; v[a[i].y]=true; f[a[i].y][0]=a[i].x; } int root; for (int i=1;i<=n;i++) if (!v[i]) { root=i; break; } dfs(1,root); for (int j=1;j<=16;j++) for (int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; int p,q; scanf("%d%d",&p,&q); printf("%d\n",lca(p,q)); } }
相关文章推荐
- LCA算法解析-Tarjan&倍增
- LCA算法解析-Tarjan&倍增
- tarjan&&LCA模板
- LCA Tarjan及倍增模板(POJ 1330)
- luogu3379 最近公共祖先(LCA) tarjan 倍增
- 最近公共祖先LCA(Tarjan与DFS--ST倍增)
- POJ 1330 Nearest Common Ancestors(tarjan , 倍增法求LCA) - from lanshui_Yang
- poj 1330 LCA (倍增+离线Tarjan)
- LCA三种算法学习(离线算法tarjan+在线算法转rmq+在线倍增)例题poj1330、1470;hdu4547、2874
- 最近公共祖先(LCA):tarjan与倍增
- 洛谷P1967货车运输(最大生成树 && LCA倍增)
- Tarjan&LCA题集【夏天的风】
- [置顶] 对LCA、树上倍增、树链剖分(重链剖分&长链剖分)和LCT(Link-Cut Tree)的学习(填坑ing)
- bzoj 1787 && bzoj 1832: [Ahoi2008]Meet 紧急集合(倍增LCA)
- c++最近公共祖先LCA(倍增算法和tarjan)
- hiho一下 第十五周 最近公共祖先·二 - 更新一下tarjan离线LCA模板
- HDU 3078 - Network (LCA)【tarjan离线/DFS倍增】
- 【题】【二分答案&倍增(lca)】NKOJ 3560 运输计划
- 【转】Tarjan&LCA题集
- 洛谷 P1967 货车运输(Kruskal最大生成树&&倍增lca)