最近公共祖先 模板 裸题

来源:互联网 发布:开票软件自动更新多久 编辑:程序博客网 时间:2024/06/04 19:17

最近公共祖先

Time Limit:10000MS  Memory Limit:65536K
Total Submit:75 Accepted:67 
Case Time Limit:1000MS

Description

给出一棵有N(编号1到N)个节点的有根树,求出指定节点对的最近公共祖先! 
 
对于树中节点x而言,从根节点到达x的这一条路径中经过的所有节点,都称为x的祖先。 
如上图所表示的树中, 根节点为8。8、4、10、16都是12的祖先。对于6和12这对节点而言,从6出发往上朝根走和从12出发往上朝根走的两条路径最早交汇的地点是4号节点,因此4号点是6和12的最近公共祖先。 
同理,11和9的最近公共祖先是8; 10和3的最近公共祖先是10;2和7的最近公共祖先是4......

Input

第一行,一个整数N。表示树中节点总数 
接下来N-1行,每行两个整数x和y,表示x是y的父亲。 
接下来一行,一个整数M,表示询问的总数 
接下来M行,每行两个整数a和b,表示询问a和b的最近公共祖先。

Output

M行,每行一个整数,表示对应询问的答案。

Sample Input

输入样例1:16 1 148 510 165 94 68 44 101 136 1510 116 710 216 38 116 12316 714 93 10输入样例2:52 33 43 11 523 54 5

Sample Output

输出样例1:4810输出样例2:33

Hint

2<=N<=10000 
1<=M<=10000

Source

改编自POJ1330


<pre name="code" class="cpp">#include<cstdio>#include<vector>#include<cmath>using namespace std;#define maxn 10009#define maxm 10009int dep[maxn], fa[maxn][20], /*BigS 这个变量废弃了*/;vector <int> edge[maxn];void fdepfa(int cur)//计算各点的深度和祖先 {int i, k;dep[cur]=dep[fa[cur][0]]+1;//当前点的深度=父亲节点的深度+1 k=ceil(log(dep[cur])/log(2));//最多网上跳 k 次 for(i=1; i<=k; i++){fa[cur][i]=fa[fa[cur][i-1]][i-1];}vector<int>::iterator it;//深搜儿子节点 for(it=edge[cur].begin(); it!=edge[cur].end(); it++){fdepfa(*it);}}int lca(int x, int y){int i, k, s;if(dep[x]<dep[y])swap(x, y);//保证x节点始终在y节点之下,即保证x的深度小于y的深度 k=dep[x]-dep[y];//把x跳到和y同一深度需要向上走 k 层 //for(i=0; i<=BigS; i++)s=ceil(log(dep[x])/log(2));//有这么一天,我把上面那句话改了 for(i=0; i<=s; i++){if(k&(1<<i))x=fa[x][i];//要走k步,按位走k步 }if(x==y)return x;//如果x的编号等于y的编号,运气太好,y就是x的祖先 s=ceil(log(dep[x])/log(2));//可惜x和y没有直接祖孙关系,只有共同的祖先,最多往上跳s次 for(i=s; i>=0; i--)if(fa[x][i]!=fa[y][i])//从深度小的祖先对照,找到第一个不相同的,直接跳上去 {x=fa[x][i];y=fa[y][i];}return fa[x][0];}int main(){int i;int n, m, x, y, a, b;scanf("%d", &n);//BigS=log(n)/log(2);//最大倍增深度 ,没什么用 for(i=1; i<n; i++)//只有n-1条边 {scanf("%d%d", &x, &y);fa[y][0]=x;//y的父亲为x edge[x].push_back(y);//vector存边 }for(i=1; i<=n; i++)if(fa[i][0]==0){fdepfa(i); break;}//从根节点开始计算各点深度,各点的祖先 scanf("%d", &m);for(i=1; i<=m; i++){scanf("%d%d", &a, &b);printf("%d\n", lca(a, b));//lca(a, b)计算a, b的最近公共祖先的编号 }return 0;}


<pre name="code" class="cpp">#include<cstdio>#include<vector>#include<cmath>using namespace std;#define maxn 10009#define maxm 10009int dep[maxn], fa[maxn][20];vector <int> edge[maxn];void fdepfa(int cur){int i, k;dep[cur]=dep[fa[cur][0]]+1;k=ceil(log(dep[cur])/log(2));for(i=1; i<=k; i++)fa[cur][i]=fa[fa[cur][i-1]][i-1];vector<int>::iterator it;for(it=edge[cur].begin(); it!=edge[cur].end(); it++){fdepfa(*it);}}int lca(int x, int y){int i, k, s;if(dep[x]<dep[y])swap(x, y);k=dep[x]-dep[y];s=ceil(log(dep[x])/log(2));for(i=0; i<=s; i++)if(k&(1<<i))x=fa[x][i];if(x==y)return x;s=ceil(log(dep[x])/log(2));for(i=s; i>=0; i--)if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}return fa[x][0];}int main(){int i;int n, m, x, y, a, b;scanf("%d", &n);for(i=1; i<n; i++){scanf("%d%d", &x, &y);fa[y][0]=x;edge[x].push_back(y);}for(i=1; i<=n; i++)if(fa[i][0]==0){fdepfa(i); break;}scanf("%d", &m);for(i=1; i<=m; i++){scanf("%d%d", &a, &b);printf("%d\n", lca(a, b));}return 0;}



0 0
原创粉丝点击