zoukankan      html  css  js  c++  java
  • LCA 的一些扩展算法

    (LCA) 的一些扩展问题

    一. 暴力

    一步一步跳

    算法:
    (1) 求出每个点的深度
    (2) 判断两个点是否重合,若是则该点就是 (LCA)
    (3) 否则,选择深度大的点移动到它父亲

    最坏情况下复杂度(O(n))
    随机情况下,树高度期望是(O(n~log~n)),可以放心食用
    实现简单,是理想的对拍程序
    只需要知道每个节点的父亲和深度,允许树动态改变

    二. 倍增

    不讲了

    三. (LCA) 转化为 (rmq) 问题

    (dfs) 遍历所有结点,建立三个数组
    (ver[i]) : 表示 (dfs)(i) 个访问的节点(dfs序)
    (dep[i]) : 表示 (ver[i]) 的层数
    (first[i]) : 表示 (ver[i]) 第一次出现的下标

    查找 (x,y) 的最近公共祖先 就相当于在 ([first[u],first[v]]) 区间中找 (dep) 最小的

    具体见代码

    void dfs(int u, int Dep, int f) {
        fa[u] = f ;
        vis[u] = 1 ; node[++tot] = u ;  
    	first[u] = tot ; dep[tot] = Dep ;
        rep(i, 0, siz(e[u]) - 1) {
        	int v = e[u][i] ;
        	if (vis[v]) continue ;
            dfs(v, Dep + 1, u) ;
            node[++tot] = u ; 
    		dep[tot] = Dep ;
        }
    }
    
    void st(int n) {
        int k = (int) (log(double(n)) / log(2.0)) ;
        rep(i, 1, n) dp[i][0] = i ;
        rep(j, 1, k) 
    	rep(i, 1, n + 1 - Pw[j]) {
            int a = dp[i][j - 1] ;
            int b = dp[i + Pw[j - 1]][j - 1] ;
            if (dep[a] < dep[b]) dp[i][j] = a ;
            else dp[i][j] = b ;
        }
    }
    
    int ask(int x, int y) {
        int k = (int) (log(double(y - x + 1)) / log(2.0)) ;
        int a = dp[x][k] ;
        int b = dp[y - Pw[k] + 1][k] ;
        if (dep[a] < dep[b]) return a ;
        return b ;
    }
    
    int lca(int u, int v) {
        int x = first[u], y = first[v] ;
        if (x > y) swap(x, y);
        int s = ask(x, y);
        return node[s] ;
    }
    

    四. (Tarjan)

    Tarjan是离线算法,复杂度 (O(n))

    首先把所有的询问离线

    之后遍历所有点,对于一个点 (u)

    他的儿子 (v) 如果没有遍历过那么就把 (u,v) 合并

    然后对于 (u) 的所有询问,如果可以回答的,答案就是对应 (v) 的并查集的根

    Luogu 3379 模板题

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int)a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    
    const int N = 500010 ;
    
    int n, m, Rt, qid ;
    int ans[N], fa[N], vis[N] ;
    bool flg[N] ;
    
    struct query {
    	int t, qid ;
    } ;
    
    vector <int> e[N] ;
    vector <query> q[N] ;
    
    int find(int x) {
    	return fa[x] == x ? x : fa[x] = find(fa[x]) ;
    }
    
    void dfs(int u, int ft) {
    	rep(i, 0, siz(e[u]) - 1) {
    		int v = e[u][i] ;
    		if (v == ft || vis[v]) continue ;
    		dfs(v, u) ;
    		fa[find(v)] = find(u) ;
    		vis[v] = 1 ;
    	}
    	rep(i, 0, siz(q[u]) - 1) 
    	if (!flg[q[u][i].qid] && vis[q[u][i].t]) {
    		ans[q[u][i].qid] = find(q[u][i].t) ;
    		flg[q[u][i].qid] = 1 ;
    	}
    }
    
    signed main() {
    	scanf("%d%d%d", &n, &m, &Rt) ;
    	rep(i, 1, n) fa[i] = i ;
    	rep(i, 1, n - 1) {
    		int x, y ; scanf("%d%d", &x, &y) ;
    		e[x].pb(y) ; e[y].pb(x) ;
    	}
    	rep(i, 1, m) {
    		int x, y ; scanf("%d%d", &x, &y) ;
    		q[x].pb((query){y, i}) ;
    		q[y].pb((query){x, i}) ; 
    	}
    	dfs(Rt, 0) ;
    	rep(i, 1, m) printf("%d
    ", ans[i]) ;
    	return 0 ;
    }
    
    
  • 相关阅读:
    搭建zend framework1开发环境
    动态调整UITableViewCell高度的实现方法
    实用SQL语句大全
    ios错误大全
    UITableView取消选中颜色、常用操作
    NSString的常用方法
    地图覆盖物
    iOS 录音功能的实现
    UITableView划动删除的实现
    UITableView的编辑模式
  • 原文地址:https://www.cnblogs.com/harryhqg/p/13298126.html
Copyright © 2011-2022 走看看