最近在学双连通分量,做到一个题,是LCA的,不会做就来学习了一下LCA,发现网上有好多资料,鱼龙混杂。推荐一篇因为他推荐了许多文章(感兴趣点击打开))
首先先借鉴一下他的一张图片
这基本就是这个lca的思想。
按照我的理解首先要dfs一边求出first 【u】,deep【u】,并且记录下first【u】所对应的u;
代码如下:
void dfs(int u ,int dep) { vis[u] = true; ver[++tot] = u; first[u] = tot; deep[tot] = dep; for(int i=head[u]; i!=-1; i=edge[i].next) int v = edge[i].v; if( !vis[v] ) { dfs(v,dep+1); ver[++tot] = u; deep[tot] = dep;//这两句话表示dfs的时候还要回溯到上面 } }
然后继续RMQ预处理,ST算法,这个是在上面所说的博客模板
所谓ST算法就是
令dp【i】【j】为从下标i开始,长度为(1《《j)长的元素的最小值,那么状态转移方程就是
dp【i】【j】=min{dp【i】【j-1】,dp【i+(2<<(j-1))】【j-1】}
void ST(int len) { int K = (int)(log((double)len) / log(2.0)); for(int i=1; i<=len; i++) dp[i][0] = i; for(int j=1; j<=K; j++) for(int i=1; i+_pow[j]-1<=len; i++) { int a = dp[i][j-1] , b = dp[i+_pow[j-1]][j-1]; if(deep[a] < deep[b]) dp[i][j] = a; else dp[i][j] = b; } }
RMQ,原理是令k为满足(1<<k)<=(r-l+1)的最大整数,则以 l 开头的,长度为2的k次方的区间长度覆盖了查询区间(l,r),由于是求最小值,所以没有关系,但是如果是累加的话,就要错,那么他的结果就是min(dp【l】【k】,dp【r+1-(1<<k)】【k】);
int RMQ(int x ,int y) { int K = (int)(log((double)(y-x+1)) / log(2.0)); int a = dp[x][K] , b = dp[y-pow[K]+1][K]; if(deep[a] < deep[b]) return a; else return b; } int LCA(int u ,int v) { int x = first[u] , y = first[v];//查找出他最先出现的地方 if(x > y) swap(x,y); int res = RMQ(x,y);//查询出的是他祖先的下标 return ver[res];//查询出的是他的祖先 }
以上就是LCA转RMQ算法,然后还有一个tarjan离线算法,去学习喽
其实ST也是tarjan的,
要换床头画了
时间: 2024-11-01 12:31:17