給定一棵有根多叉樹,請求出指定兩個點直接最近的公共祖先。
樹的構造-舉個栗子
尤拉序
儲存第一次出現的位置
使用鏈式前向星儲存樹的結構,首先求一棵樹的尤拉序,然後根據兩點的公共祖先就是尤拉序中(第一次出現時)兩點位置區間內的深度最小點,
這一定理轉化成rmq最小問題,使用st表時注意log2的複雜度比較高,st表總體速度較慢,約900ms
#include#define for(i,a,b) for(int i=a;i'9'||ch
ch=getchar();
if(ch=='-')
while('0'<=ch&&ch<='9')
return x*f;
}inline void put(int x)
int num=0;
char c[25];
while(x)
while(num)
putchar(c[num--]);
putchar('\n');
return ;
}inline int log2(int x)
inline void dfs(int pre,int cur,int level)
if(pre!=cur) }
inline void add(int a,int b)
int main()
dfs(0,s,1);
//rmq
int logh=log2(cnt);
for(int h=1;h<=logh;h++)
}\)次能到達的祖先節點,
然後讀取要求的點\(a,b\),處理成同一深度後,若\(b\)是\(a\)的祖先,則返回b,
若不是,則同時上跳\(2^}\)次,直到相等.
時間比st表快,約550ms。預處理時間複雜度o(nlogn),每次查詢時間複雜度o(logn)
#include#define for(i,a,b) for(int i=a;i'9'||ch
ch=getchar();
if(ch=='-')
while('0'<=ch&&ch<='9')
return x*f;
}inline void put(int x)
int num=0;
char c[25];
while(x)
while(num)
putchar(c[num--]);
putchar('\n');
return ;
}inline int log2(int x)
inline void add(int a,int b)
void dfs(int cur,int pre)
} return jump[x][0];//返回父節點
}int main()
dfs(s,0);
for(i,0,m)
return 0;
}
先選擇乙個節點u為根節點,從根節點開始搜尋。(標記u已訪問過)
遍歷該點u的所有兒子節點v,並標記v已訪問過。
若v還有兒子節點,對v重複ii操作,否則進入下一操作。
把v合併到u上(並查集)。
把當前的點設為u,遍歷與u有詢問關係的節點v。
如果v在之前已經被訪問過,那麼u和v的最近公共祖先就是v通過並查集合並後的父親節點(注意是合併後),即當前的find(v)。
預處理時間複雜度o(nlogn),每次查詢時間複雜度o(1),總時間複雜度是o(nlogn+q),約400ms
tarjan偽**
tarjan(u)//marge和find為並查集合並函式和查詢函式
for each(u,e) //訪問所有和u有詢問關係的e
}
#include#define for(i,a,b) for(int i=a;i'9'||ch
ch=getchar();
if(ch=='-')
while('0'<=ch&&ch<='9')
return x*f;
}inline void put(int x)
int num=0;
char c[25];
while(x)
while(num)
putchar(c[num--]);
putchar('\n');
return ;
}inline int log2(int x)
inline void add(int a,int b)
inline void vadd(int a,int b)
inline int find(int x)
void tarjan(int u)
for(int i=vhead[u];i;i=vedges[i].next) }
}int main()
for(i,0,m)
tarjan(s);
for(int i=1;i<=m;i++)
put(lca[i*2]);
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的樹,求某兩個點的最近公共祖先。思路 預處理出每個點的深度再一...