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的樹,求某兩個點的最近公共祖先。思路 預處理出每個點的深度再一...