洛谷 3379 LCA模板
本人最近剛接觸到LCA,先是在vjudge的團隊裏做到了一到倍增LCA找父親(codeforces 519E),然後求出有多少個點到訪問的x,y這兩個節點的距離相同。
洛谷題號:CF519E
鏈接:https://www.luogu.org/problemnew/show/CF519E
我有一個程序瘋狂無限制第7個點爆MLE到現在都不知道為什麽。
代碼請見:https://www.luogu.org/discuss/show?postid=48843
希望有大佬能夠指點迷津。 可以在洛谷評論也可以在這裏評論,或者私信我的qq也行
QQ:2320993191
但是雖然說是一直MLE過不去這道題目,但是對LCA我初步有了一定的理解,然後我就按耐不住激動地心情,來到洛谷做了一下模板LCA。
這裏我要講兩個註意點:
1.在我們在做dfs預處理f數組的時候,i不能倒著掃,因為每一個f[x][i]都來源於比自己要小的f[f[x][i-1]][i-1],所以如果倒著掃就會出現問題。我剛開始也就是因為這個錯了。
2.當我們在把x節點和y節點跳到同一個深度以及之後達到同一深度再往上跳的時候,i都需要倒著掃,這裏我們需要想一下,我舉一個例子,如果我現在需要向上跳5個深度,那麽如果我i=1的時候跳(1<<1)也就是2個深度的時候,我還需要跳3個深度,但是當我下一次要跳的時候 i已經等於2了,又因為(1<<2)等於4了,已經超過了3個深度所以已經不能跳了。所以必須是要倒著掃的,其次我們在想一下,即使我們倒著掃,我們也無法判斷,這次往上跳完了之後到底是已經在我們所需要求的LCA只上,還是恰好是我們需要求的LCA,所以當f[x][i]==f[y][i]的時候我們幹脆不跳,這樣等我們操作完了之後,只需要在往上跳一個深度,那麽那個節點就一定是我們所想要的LCA. 下面是我的AC代碼,大家可以參考一下。如果有什麽地方有問題歡迎大家提出,也隨時歡迎大家來找我一起討論OI問題,其他問題也可以啦哈哈哈哈哈哈哈,比如說抑郁不得誌(這麽大佬的你們肯定不會抑郁不得誌的),我可以幫你解脫煩惱O(∩_∩)O哈哈~
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=1000010;
int n,m,s,x,y,ans,top;
int first[N],next[N],get[N],deep[N];
int f[N][32];
void add(int x,int y){
get[++top]=y;
next[top]=first[x];
first[x]=top;
}
void dfs(int x,int fa,int deep_){
deep[x]=deep_;
f[x][0]=fa;
for (int i=1;(1<<i)<=deep_;++i)
f[x][i]=f[f[x][i-1]][i-1];
for (int i=first[x];i;i=next[i]){
int v=get[i];
if (v==fa) continue;
dfs(v,x,deep_+1);
}
}
void LCA(int a,int b){
if (deep[a]>deep[b]) swap(a,b); //a淺 b深
for (int i=31;i>=0;--i){
if (deep[b]-(1<<i)<deep[a]) continue;
b=f[b][i];
}
if (a==b) {
ans=a;
return;
}
for (int i=31;i>=0;--i){
if(f[a][i]==f[b][i]) continue;
a=f[a][i];
b=f[b][i];
}
ans=f[a][0];
}
int main(){
//freopen(".in","r",stdin);
scanf("%d%d%d",&n,&m,&s);
for (int i=1;i<=n-1;++i){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
dfs(s,0,1);
for (int i=1;i<=m;++i){
scanf("%d%d",&x,&y);
LCA(x,y);
printf("%d\n",ans);
}
}
洛谷 3379 LCA模板