hihoCoder1232 Couple Trees LCA倍增算法+二分

来源:互联网 发布:如何评价阿凡达 知乎 编辑:程序博客网 时间:2024/06/05 07:11

题意:给你两颗树,节点编号都是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[N];queue<int>q;struct tree{int p[N][21],dep[N];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;}


0 0
原创粉丝点击