洛谷3379
基本思路:要求兩個點的最近公共祖先,首先我們用乙個陣列fa[x][i]來表示節點x的向上2^i層的祖先編號,先dfs求出每個點的深度和預處理fa陣列。再求兩個節點的最近公共祖先時,先讓深度大的跳到相同的一層,再嘗試以log2(depth[x])的跨度跳至祖先節點,相同時不跳(因為可能不是最近的公共祖先),不同時再跳,最後輸出跳後的那個點的父親節點即可
#include #include #include using namespace std;
vectorg[500005];
int depth[500005],fa[500005][25],vis[500005];
void dfs(int x,int fath)
for( int i = 0 ; i < g[x].size() ; i++ ) }
//從最大可以跳的步數開始跳(一定是2^i),
//如果跳的到的位置一樣,就不跳,如果不一樣才跳,每次跳的路程是前一次的一半
int lca(int x,int y)
if( x == y ) return x; //特判:如果y是x的祖先,就直接輸出(後面輸出的是它的父節點)
for( int i = log2(depth[x]]) ; i >= 0 ; i-- ) }
return fa[x][0]; //執行完了這一段到的點不是最近公共祖先,但是,它們再往上跳一層,就到了
}int main()
dfs(root,0);
for( int i = 0 ; i < q ; i++ )
return 0;
}
rmq求lca
基本思路:
在 dfs 的過程中,退出乙個子樹之後就不會再進入了。這是個很好的性質。
所以很顯然,乙個子樹中深度最淺的節點必定是該子樹的樹根。
顯然,兩個節點的 lca 不僅是兩個節點的最近公共祖先,而且是囊括這兩個節點的最小子樹的根,即囊括這兩個節點的最小子樹中的深度最小的節點。
從離開 a 到進入 b 的這段尤拉序必然包括所有這對點之間的簡單路徑上的所有點,所以我們考慮求得這段尤拉序中所包含的節點中的深度最小的點即其 lca 。配合st表即可在o(1)的時間內解出。
#include #include #include #include using namespace std;
vectorg[500005];
vectoreuler;
int deep[500005],first[500005],vis[500005];
int dp[1000005][25];
void dfs(int x,int d) //dfs求尤拉序和first陣列
}void st()
for (int j = 1; (1else dp[i][j] = dp[i][j-1];}}
}int lca(int x,int y)
dfs(root,1);
st();
for( int i = 0 ; i < m ; i++ )
return 0;
}
求LCA(最近公共祖先)
演算法1 樹上倍增 hdu 2586 include include include define maxn 40000 5 define inf 999999999 using namespace std int n,m,t,q,head maxn x,y,z,vis maxn fa maxn c...
LCA求最近公共祖先
parent i j 表示節點u的第2 j個祖先 dis i dfs時間戳,即節點到根節點距離,即深度 const int pow 18 const int maxn 5e5 10 int parent maxn pow 10 parent i j 表示節點u的第2 j個祖先 vectoredge ...
最近公共祖先 LCA 最近公共祖先
直接暴力搜尋參考 普通搜尋每次查詢都需要 樸素演算法是一層一層往上找,倍增的話直接預處理出乙個 具體做法是 維護乙個 的關係來線性求出這個陣列 int anc n 31 int dep n 記錄節點深度 void dfs int u,int parent for int i 0 i g u size...