【總結】LCA的4種求法
阿新 • • 發佈:2018-10-16
spa 另一個 int 可能 同學 需要 continue 合並 沒有
前言
LCA的求法有多重多樣,總結下來是下面這4種.希望大家可以加油!
暴力求LCA
我們考慮dfs求出每一個點的父親(在當前根下),然後直接先暴力跳到同一個深度,再同時跳
void dfs(int u,int f){ fa[u]=f;dep[u]=dep[f]+1; for(re int i=front[u];i;i=e[i].nxt){ int v=e[i].to; if(v==f)continue; dfs(v,u); } } int lca(int u,int v){ if(dep[u]<dep[v])swap(u,v); while(dep[u]!=dep[v])u=fa[u]; while(u!=v)u=fa[u],v=fa[v]; return u; }
倍增求LCA
我們考慮每一次跳1個父親的速度太慢,那麽怎麽優化呢?
這個時候就需要用到倍增這種思想了.
沒有學過倍增的同學可以先寫一下ST表,可能會對倍增有比較深刻的理解.
我們假設這樣子一個變量\(f[i][j]\)表示點\(i\)的第\(2^j\)個父親是哪個節點.
因為每一個數都可以二進制表示,所以我們考慮每一次從大到小枚舉跳的東西,然後就可以做到\(\Theta(n\ log(n))\)
void dfs(int u,int fa){ dep[u]=dep[fa]+1; for(re int i=front[u];i;i=nxt[i]){ int v=to[i]; if(v!=fa)dfs(v,u),f[0][v]=u; } } int lca(int a,int b){ if(dep[a]<dep[b])swap(a,b); for(re int i=20;~i;i--) if(dep[a]-(1<<i)>=dep[b]) a=f[i][a]; if(a==b)return a; for(re int i=20;~i;i--) if(f[i][a]!=f[i][b]) a=f[i][a],b=f[i][b]; return f[0][a]; }
樹鏈剖分求LCA
考慮把一個樹分成輕鏈與重鏈,然後直接跳鏈就好了.
void dfs1(int u,int f){ fa[u]=f;siz[u]=1;dep[u]=dep[f]+1; for(re int i=front[u];i;i=e[i].nxt){ int v=e[i].to; if(v==fa[u])continue; dfs1(v,u); siz[u]+=siz[v]; if(siz[v]>siz[son[u]])son[u]=v; } } void dfs2(int u,int tp){ top[u]=tp; if(!son[u])return; dfs2(son[u],tp); for(re int i=front[u];i;i=e[i].nxt){ int v=e[i].to; if(v==fa[u] || v==son[u])continue; dfs2(v,v); } } void swap(int &a,int &b){ int tmp=a;a=b;b=tmp; } int lca(int u,int v){ while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]])swap(u,v); u=fa[top[u]]; } return dep[u]>dep[v]?v:u; }
Tarjan求LCA
考慮把每一個詢問當做一條邊處理,那麽如果這兩個都被訪問了,顯然另一個點的祖先一定是他們的LCA.
所以可以很容易地寫出這一段代碼.(註意最後合並)
int find(int x){
if(f[x]!=x)f[x]=find(f[x]);
return f[x];
}
void Add(int u,int v){
to[++cnt]=v;nxt[cnt]=front[u];
front[u]=cnt;
}
void Addques(int u,int v,int Id){
toq[++cnt]=v;
id[cnt]=Id;nxtq[cnt]=frontq[u];
frontq[u]=cnt;
}
void dfs(int u,int fa){
b[u]=1;
for(int i=front[u];i;i=nxt[i]){
int v=to[i];
if(v!=fa){
dfs(v,u);
for(int j=frontq[v];j;j=nxtq[j]){
int vv=toq[j];
if(b[vv])ans[id[j]]=find(vv);
}
int uu=find(u),vv=find(v);
if(uu!=vv)f[vv]=uu;
}
}
}
【總結】LCA的4種求法