LCA是什么?
最近公共祖先,就是树上的两个点它们深度最大(离根节点最远)的公共祖先。算法
1. 朴素算法。时间复杂度O(n×q)。并没有实际意义。 2. 倍增算法。时间复杂度O((n+q)logn)。倍增算法
它的特点是:每次向祖先跳的距离,不是1,而是2k,这样可以省很多时间。 记录每个点的fai,j,表示i号节点向根跳2j步的点,如果跳过了根记为0。那么显然,第一步是要把要询问的两个节点都跳到同一深度,第二步同时往根跳。这样就找到了这两个点的LCA。代码
#include#include const int maxn=500000;inline int read(){ int x=0,f=1; char ch=getchar(); while((ch<'0')||(ch>'9')) { if(ch=='-') { f=-f; } ch=getchar(); } while((ch>='0')&&(ch<='9')) { x=x*10+ch-'0'; ch=getchar(); } return x*f;}inline int print(int x,int mode=0){ if(!mode) { if(!x) { putchar('0'); return 0; } if(x<0) { putchar('-'); x=-x; } } if(x) { print(x/10,1); putchar(x%10+'0'); } return 0;}struct tree{ int pre[maxn*2+10],now[maxn+10],son[maxn*2+10],tot; int deep[maxn+10],fa[maxn+10][20]; int ins(int a,int b)//建图 { tot++; pre[tot]=now[a]; now[a]=tot; son[tot]=b; return 0; } int dfs(int u,int father)//预处理,把每个点的fa都处理出来 { deep[u]=deep[father]+1; fa[u][0]=father; for(int i=1; i<=19; i++) { fa[u][i]=fa[fa[u][i-1]][i-1]; } int j=now[u]; while(j) { int v=son[j]; if(v!=father) { dfs(v,u); } j=pre[j]; } return 0; } int lca(int x,int y)//求LCA { if(deep[x] =0; i--) { if(deep[fa[x][i]]>=deep[y]) { x=fa[x][i];//将深度大点的往上跳,当然不能跳过另一个点 } } if(x==y) { return x;//如果找到答案了退出 } for(int i=19; i>=0; i--) { if(fa[x][i]!=fa[y][i])//同时向上跳,当然不能跳到一起去 { x=fa[x][i]; y=fa[y][i]; } } return fa[x][0];//最后再跳到一起,那么这个点一定是LCA }};tree t;int n,m,root;int main(){ n=read(); m=read(); root=read(); for(int i=1; i