您的位置:首页 > 其它

hihoCoder1232 Couple Trees LCA倍增算法+二分

2015-10-09 23:37 363 查看
题意:给你两颗树,节点编号都是1-n。根节点都为1,且父节点编号必大于子节点。有m次询问,每次给出两个坐标x,y,通过换算(与上一次询问结果有关),得到了两个节X,Y,

问这两个节点的在这两颗树中的最近公共祖先。

方法:求出每个点的倍增父节点,然后每次X,Y朝着倍增父节点尽量移动(尽量保证移的位置的节点大于另一个节点),如果不能保证,至少也得往前移一位。
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
#include <vector>
using namespace std;
const int N=1e5+5;
vector<int>G
;
queue<int>q;
struct tree{
int p
[21],dep
;
void init(int n){
for(int i=1;i<=n;i++)
for(int j=0;j<=20;j++)
p[i][j]=i;
}
void BFS(int n){
q.push(1);
dep[1]=1;
while(!q.empty()){
int cur=q.front();q.pop();
for(int i=0;i<G[cur].size();i++){
dep[G[cur][i]]=dep[cur]+1;
q.push(G[cur][i]);
}
for(int j=1;j<=20;j++){
p[cur][j]=p[p[cur][j-1]][j-1];
}
}
}
void build(int n){
int u;
for(int i=1;i<=n;i++)G[i].clear();
for(int i=2;i<=n;i++){
scanf("%d",&u);
p[i][0]=u;
G[u].push_back(i);
}
BFS(n);
}
}A,B;
int Find(int *p,int n,int val){
int l=0,r=n,mid;
int ret=0;
while(l<=r){
mid=(l+r)>>1;
if(p[mid]>=val){
ret=max(ret,mid);
l=mid+1;
}
else r=mid-1;
}
return p[ret];
}
int solve(int x,int y,int n){
if(x==y)return x;
while(true){
if(x>y){
x=Find(A.p[x],20,y);
}
else{
y=Find(B.p[y],20,x);
}
if(x==y)return x;
}
}
void work(){
int n,m;
while(~scanf("%d%d",&n,&m)){
A.init(n);B.init(n);
A.build(n);B.build(n);
int pre=0;
int x,y;
while(m--){
scanf("%d%d",&x,&y);
x=(x+pre)%n+1;
y=(y+pre)%n+1;
pre=solve(x,y,n);
printf("%d %d %d\n",pre,A.dep[x]-A.dep[pre]+1,B.dep[y]-B.dep[pre]+1);
}
}
}
int main(){
//freopen("data.in","r",stdin);
work();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: