RMQ求LCA其實非常簡單的啦
我們需要理解兩個基本的工具:
1.歐拉序列;
2.線段樹,二叉搜索樹或者其它基本區間尋求最值的方法;
所以說LCA和區間有什麼關係?
舉個栗子:
我們將歐拉序列E打出:
【1,2,4,2,5,2,1,3,6,3,1】(先自己想想怎麼實現)
在打印序列的同時記錄下每個節點第一次出現的位置R
【1,2,8,3,5,9】
另外別忘了給歐拉序列標深度L
【1,2,3,2,3,2,1,2,3,2,1】
接下來區間最值的作用就發揮了作用了:
比如我們要找4和5LCA,我們只需要在R數組中找到【3,5】中深度最小的節點就行了;
而對應的區間可以通過R數組來確定;
接下來是moban(蒟蒻只能用領接鏈表建):
首先是歐拉序列的打印:
void dfs(int u,int dep)
{ tot++;
R[u]=tot;//這裏是第一次出現的位置;
L[tot]=dep;
E[tot]=u;
vis[u]=true;
for(int i=head[u];i!=0;i=nex[i])
{int v=to[i];
if(!vis[v]){
dis[v]=dis[u]+w[i];
dfs(v,dep+1);
E[++tot]=u;//別忘了回到u節點記錄;
L[tot]=dep;}
}
}
接下來是ST對序列進行處理(我們記錄的不是最小深度,而是最小深度對應的節點)
不明白ST的可以看我的另一篇博客:https://blog.csdn.net/Wyt_code/article/details/83832104
void found()//STmoban不多說;
{ for(int i=1;i<=tot;i++)
f[i][0]=i;
int n=(int)(log(tot)/log(2));
for(int j=1;j<=n;j++)
for(int i=1;i<=tot;i++)
if(i+(1<<j)-1<=tot){
int a=f[i][j-1];int b=f[i+(1<<j-1)][j-1];
if(L[a]<L[b]) f[i][j]=a;//注意是記錄下標以便確定節點;
else f[i][j]=b;
}
}
接下來是RMQ和LCA的查詢(爲了便於理解我分成兩個板塊)
int RMQ(int l,int r)
{int j=(int)(log(r-l+1)/log(2));
int a=f[l][j];int b=f[r-(1<<j)+1][j];
return L[a]<L[b]?a:b;//還是返回數組對應下標;
}
int LCA(int l,int r)
{ l=R[l];r=R[r];//確定區間;
if(l>r) swap(l,r);
return E[RMQ(l,r)];//讀求下標對應節點;
}
emmmm好像就這些了