日常题解——LCA和RMQ1

  • Tarjan算法:DFS+并查集求LCA
  • RMQ查询区间最大最小值,st(动态规划写法)
  • dfs序/dfn序 -> 使用dfn编号构建的dfs序,在dfs序上rmq查询区间最小值得到的就是lca的编号,映射得到的是节点

板子

话不多说,贴代码

这个代码没有具体的建树,只有核心的代码原理和代码实现,建树用python的邻接表最方便,遍历子节点部分参照Python遍历邻接表逻辑理解

  • public class LCA_RMQ {
        public static void main(String[] args) {
    
        }
    
        //Tarjan算法:dfs+并查集求lca,
        /* 1.遍历节点u的所有子节点
        *  2.回溯时子节点合并到父节点所在集合, -> 最近公共祖先:维护集合深度最低的节点
        *  3.标记已遍历
        *  4.查询该节点与v的公共祖先
        * dfs(u):
        *   遍历儿子
        *   回溯合并
        *
        *   遍历每个询问,查询已经构建并查集的v与当前节点u的lca(u,v)=v所在集合
        *
        * */
    
        static final int N = 10010;
        static int[][] que = new int[N][N],edges = new int[N][N];
        static boolean[] vis = new boolean[N];
        static int[] cnt = new int[N];
    
        static int[] parent = new int[N];
        public void init(){
            for(int i=0;i f[i,j]:以i为初始节点,区间长度为2^j的区间内的最小值。转移:f[i,j] = min(f[i,j-1], f[i+2^(j-1),j-1])
    
        /* st表注意事项:1.不用全部位置都填完,二进制表示不够(没有覆盖到的区间在上一次就考虑到选择了最小值就不用再顾及)
        * 1 2 3 4 5 6 7 8 9 10 (1 1 3 3 5 5 7 7 9)
        * */
    
        //dfs序(dfn序):编号层次遍历,找到公共祖先所在层:
        //dfs:2 5 11 5 12 5 2 6
        /*        2                     2
        *        /  \                  / \
        *       5    6                3   6
        *      / \                   / \
        *     11 12                 4   5
        *     dfs序                  dfn编号
        *
        * dfn编号后:2 3 4 3 5 3 2 6
        *  lca(6,11):11和6之间dfn对应编号最小的数就是lca的编号
        * */
    
        static int[][] st;
        public static void rmq_st(int[] nums){
            int n = nums.length;
            //1.初始化st表,j=0时,区间长度为1,就是原数组
            int mutiple = (int)(Math.log(nums.length*1.0)/Math.log(2.0));//j是2的倍数,t是能扩展的最大倍数
            st = new int[n][1<9
            for(int j=1;j<=mutiple;j++){
                int upper = n - (1< 建立新编号与旧值的映射关系
            * dfs序:记录第一次出现的位置
            * */
            int tmp = ++num;
            dfs_sequence[++dfs_cnt] = tmp;
            fa[tmp] = x;
            first[x] = dfs_cnt;
    
            for(int v : edges[x]){
                //遍历所有x的子节点v
                if(v==father)continue;
                st_dfs(v,x);
                dfs_sequence[++dfs_cnt]=tmp;//出节点记录
            }
        }
    
        public static int rmq_find(int l, int r){
            int m = (int)(Math.log(r-l+1)/Math.log(2));
            st_dfs(0,0);
            return st[l][r];
        }
    
        public static int rmq_lca(int l, int r){
            if(first[l]>first[r]){int t=l;l=r;r=t;}
            int k = rmq_find(l,r);
            return fa[k];
        }
    }
    

你可能感兴趣的:(深度优先,算法,图论)