日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

LCA与RMQ

發(fā)布時(shí)間:2024/4/17 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LCA与RMQ 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、什么是LCA?

??????LCA:Least Common Ancestors(最近公共祖先),對(duì)于一棵有根樹(shù)T的任意兩個(gè)節(jié)點(diǎn)u,v,求出LCA(T, u, v),即離跟最遠(yuǎn)的節(jié)點(diǎn)x,使得x同時(shí)是u和v的祖先。

二、算法分類

  求LCA的算法很多,按照是否在線可以分為在線算法和離線算法。
??????在線算法:用比較長(zhǎng)的時(shí)間做預(yù)處理,但是等信息充足以后每次回答詢問(wèn)只需要用比較少的時(shí)間。
??????離線算法:先把所有的詢問(wèn)讀入,然后一起把所有詢問(wèn)回答完成,不是本文所講,Click here

三、在線算法

  (1)什么是RMQ?

  RMQ:給出一個(gè)數(shù)組A,回答詢問(wèn)RMQ(A, i, j),即A[i...j]之間的最值的下標(biāo)。

  (2)RMQ算法,不是本文所講,Click here

  (3)RMQ與LCA?

  假設(shè)一顆有根樹(shù),如圖所示:

  

  我們可以通過(guò)深搜(從1節(jié)點(diǎn)開(kāi)始)得到這樣一個(gè)序列:

  歐拉序列V:1 2 1 3 4 3 5 6 5 7 5 3 1

  深度序列D:0 1 0 1 2 1 2 3 2 3 2 1 0

  First:1 2 4 5 7 8 10

  First表示節(jié)點(diǎn)i在歐拉序列V中第一次出現(xiàn)的位置

  

  現(xiàn)在比如我們要求LCA(4,7)

  那么找到節(jié)點(diǎn)4和7第一次出現(xiàn)的位置即:First(4)=5,First(7)=10

  對(duì)應(yīng)到歐拉序列V中區(qū)間[5,10]即:4 3 5 6 5 7

  發(fā)現(xiàn)正好是以3為根的子樹(shù),然我我們找到這幾個(gè)數(shù)中深度最小的即D(3),說(shuō)明3就是4和7的最近公共祖先

?

  同理再比如說(shuō)要求LCA(2,5),First(2)=2,First(5)=7,找到對(duì)應(yīng)區(qū)間[2,7]即2 1 3 4 3 5

  然后找到深度最小的即1,說(shuō)明1就是2和5的最近公共祖先。

四:例題

  HDU 2586

?

  AC CODE:

  

#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; #define min(a,b) ((a)<(b)?(a):(b)) #define N 40010 #define M N*2struct edge {int u,v,w,next; }edge[M]; int tot,head[N];int n,m; int idx; bool vis[N]; int ver[2*N]; int dep[2*N]; int first[N]; int dis[N]; int dp[2*N][20];void init() {tot=0;memset(head,-1,sizeof(head)); } void add(int u,int v,int w) {edge[tot].u=u;edge[tot].v=v;edge[tot].w=w;edge[tot].next=head[u];head[u]=tot++; } void init2() {idx=0;dis[1]=0;memset(vis,0,sizeof(vis)); } void dfs(int u,int d) {vis[u]=1;ver[++idx]=u;first[u]=idx;dep[idx]=d;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].v;if(!vis[v]){int w=edge[i].w;dis[v]=dis[u]+w;dfs(v,d+1);ver[++idx]=u;dep[idx]=d;}} } void ST(int n) {int i,j;for(i=1;i<=n;i++) dp[i][0]=i;for(j=1;(1<<j)<=n;j++){for(i=1;i<=n;i++){if(i+(1<<j)-1<=n){int a=dp[i][j-1];int b=dp[i+(1<<(j-1))][j-1];dp[i][j]=dep[a]<dep[b]?a:b;}}} } int RMQ(int i,int j) {int k=(int)(log((double)(j-i+1))/log(2.0));int a=dp[i][k],b=dp[j-(1<<k)+1][k];return dep[a]<dep[b]?a:b; } int LCA(int u,int v) {int x=first[u];int y=first[v];if(x>y) swap(x,y);int res=RMQ(x,y);return ver[res]; } int main() {int T;scanf("%d",&T);while(T--){init();scanf("%d%d",&n,&m);for(int i=1;i<n;i++){int u,v,w;scanf("%d%d%d",&u,&v,&w);add(u,v,w);add(v,u,w);}init2();dfs(1,0);ST(2*n-1);while(m--){int u,v;scanf("%d%d",&u,&v);int lca=LCA(u,v);printf("%d\n",dis[u]+dis[v]-2*dis[lca]);}}return 0; }

?

轉(zhuǎn)載于:https://www.cnblogs.com/hate13/p/4584531.html

總結(jié)

以上是生活随笔為你收集整理的LCA与RMQ的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。