最近公共祖先lca

2021-09-24 20:57:40 字數 3517 閱讀 3922

lca-最近公共祖先

兩個點在樹上距離最近的公共祖先節點

lca有主要的兩種演算法

1.tarjan:離線演算法,複雜度o(n+q)

倍增o(nlogn)查詢

怎麼求lca?

1.先將深度大的移動到小的一樣深

2.然後同時盡往上跳,但沒就是沒有跳過lca點,最後會調到lca的兩個子節點上

**:1.建樹並預處理每個點的深度,每個點的第2^i個祖先的

2.求lca,從大到小列舉,讓深度大的點一直往上跳,但一種》=(深度小的)

判斷是否移動到同一點,如果同一點,直接返回

3.兩個點在同一深度,這時就方便一起往上跳,但是就是不能跳到同一點,最後會跳到lca的兩個子節點上

建樹&&預處理:

void dfs(int x,int fa)//件樹,預處理每個節點的深度與第2^i個祖先

}

lca部分**:

因為預處理出的是第2^i個祖先,所以滿足單調性,可以從大到小直接列舉

int lca(int x,int y)

if(x==y)//y是x的祖先

return x;

for(int i=20;i>=0;i--)//一起往上跳,但是就是不能跳到同一點,最後會跳到lca的兩個子節點上

return grd[x][0];

}

模板題:

洛谷p3389,求lca點

#include#define maxn 1000005

using namespace std;

int to[maxn<<1],next1[maxn<<1],head[maxn<<1];

int tot=0;

int down[maxn];

int grd[maxn][33];

void add(int u,int v)

void dfs(int x,int fa)//件樹,預處理每個節點的深度與第2^i個祖先

}int lca(int x,int y)

if(x==y)//y是x的祖先

return x;

for(int i=20;i>=0;i--)//i很大當然是同一祖先,直接從大到小列舉

return grd[x][0];

}int main()

dfs(root,0);

while(m--)

return 0;

}

感謝:

求距離:

lca_tarjan演算法:

#include#define pb push_back

#define maxn 100005

#define ll long long

using namespace std;

int to[maxn*2],next1[maxn*2],val[2*maxn],head[maxn*2];

int f[maxn];

int dis[maxn];

int vis[maxn];

int lca[maxn];

int ans[maxn];

struct node

;vectorque[maxn];

int tot,n;

void init()

}void add(int x,int y,int z)

void add_que(int a,int b,int id));}

int get(int x)

void tarjan(int x)

int sz=que[x].size();

for(int i=0;ib)

swap(a,b);

add(a,b,c);

}for(int i=1;i<=m;++i)

else

}tarjan(1);

for(int i=1;i<=m;++i)

printf("%d\n",ans[i]);}}

lca_rmq:

#include using namespace std;

const int maxn=200005;

int n,m,tot,time1;

int to[maxn],val[maxn],next1[maxn],head[maxn];

int deep[maxn];

int in[maxn],out[maxn];

int st[maxn*2][20];

void init()

void add(int u,int v,int c)

void dfs(int x,int pre)

}out[x]=time1;

}void get_st(int n)

}return 0;

}

樹上第k小

題意:求樹上兩點間路徑第k小

解析:陣列上建主席樹是root[i]在root[i-1]的基礎上建鏈

樹上建主席樹是root[i]在root[fa[i]]的基礎上建立鏈

樹上兩點間的路徑有且僅有一條,且必過lca點,我們需要求lca

如果是求(a,b)的距離,呢麼d(x,y)=d(1,x)+d(1,y)-2*d(1,lca);

但是這裡不行,不能減去兩個lca,x和y都算過包含1次lca,最後也要包含一次lca,所以最後減去的是fa(lca).要保留乙個lca點

ac:

#include#define max 100005

#define maxn 3000005

using namespace std;

int a[maxn],b[maxn],root[maxn];

int l[maxn],r[maxn];

int sum[maxn];

int tot=0,num=0,cnt=0;

int to[max<<2],nxt[max<<2],head[max<<2];

int down[max<<2];

int grd[100005][23];

void add(int u,int v)

int build(int l,int r)

return now;

}int update(int pre,int l,int r,int k)

return now;

}int query(int pre,int now,int lca,int flca,int l,int r,int k)

void dfs(int x,int fa)

}int lca(int x,int y)//求lca

void init()

int main()

}return 0;

}

最近公共祖先 LCA 最近公共祖先

直接暴力搜尋參考 普通搜尋每次查詢都需要 樸素演算法是一層一層往上找,倍增的話直接預處理出乙個 具體做法是 維護乙個 的關係來線性求出這個陣列 int anc n 31 int dep n 記錄節點深度 void dfs int u,int parent for int i 0 i g u size...

最近公共祖先 最近公共祖先(LCA)

如題,給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。輸入格式 第一行包含三個正整數n m s,分別表示樹的結點個數 詢問的個數和樹根結點的序號。接下來n 1行每行包含兩個正整數x y,表示x結點和y結點之間有一條直接連線的邊 資料保證可以構成樹 接下來m行每行包含兩個正整數a b,表示詢問...

LCA 最近公共祖先

定義 對於有根樹t的兩個結點u v,最近公共祖先lca t,u,v 表示乙個結點x,滿足x是u v的祖先且x的深度盡可能大。另一種理解方式是把t理解為乙個無向無環圖,而lca t,u,v 即u到v的最短路上深度最小的點。現在給定乙個根為1的樹,求某兩個點的最近公共祖先。思路 預處理出每個點的深度再一...