zoukankan      html  css  js  c++  java
  • LCA转RMQ 方法(预览)

    这个方法要开倍增求 (LCA) 方法的两倍空间, 还要开额外数组记录深度和 (dfn), 各位勇士慎重。
    可以 (O(n + nlog n)) 预处理 (O(1)) 动态回答 (LCA) (常数和RMQ一样), 不谈空间缺点的话还是吊打倍增求 (LCA) 的。


    算法流程:
    算法的过程就是在便利有根树的过程中按照访问节点的次序将节点的标号插入一个队列(第一次访问该节点时插一次), 然后在访问完这个节点的某一个子节点时再插一次。

    然后将第一次访问该节点时, 将该节点的标号插入队列后队列的 (size) 记为 (fis)

    可以发现询问两个节点 (i、j)(LCA) 时, 队列中 (fis_i)(fis_j) 之间的节点, 深度最小的就是 (i、j)(LCA)

    具体证明:
    假设询问的两个节点为 (i、j)

    (i、j)不是祖先后代关系。
    即以某个节点 (k)(LCA) 的两个节点 (i、j) 分别在 (k) 的两颗不同子树内, (fis_i)(fis_j) 之间会有 (k)(见算法流程), 但绝不会有 深度小于 (k) 的节点出现((k) 的子树还没访问完, 不可能回溯)。

    (i、j)有祖先后代关系。
    不妨假设 (dep(i) leq dep(j)), 其它过程类似于上面的证明。


    Luogu的LCA模板AC代码

    //再次强调空间是倍增的两倍
    //你谷开 st[500005][21] 会T就很玄学(可能是我才疏学浅)
    #include<bits/stdc++.h>
    using namespace std;
    const int maxn = 500015;
    int n,m,s;
    int ct, hed[maxn], nxt[maxn<<1], ver[maxn<<1];
    void ad(int a,int b) {
    	ver[++ct] = b;
    	nxt[ct] = hed[a];
    	hed[a] = ct;
    }
    
    int tot, st[22][maxn<<1], fis[maxn], dep[maxn];
    void dfs(int x,int fa,int Dep) {
    	st[0][++tot] = x, fis[x] = tot, dep[x] = Dep;
    	for(int i=hed[x];i;i=nxt[i]) {
    		int y = ver[i]; if(y==fa) continue;
    		dfs(y,x,Dep+1); st[0][++tot] = x;
    	}
    }
    int calc(int x,int y) {
    	return (dep[x]<dep[y]?x:y);
    }
    
    int lca(int x,int y) {
    	int l=fis[x], r=fis[y]; if(l>r) swap(l,r);
    	int k = log2(r-l+1);
    	return calc(st[k][l], st[k][r-(1<<k)+1]);
    }
    int main()
    {
    	scanf("%d%d%d", &n,&m,&s);
    	for(int i=1;i<=n-1;++i) {
    		int x,y; scanf("%d%d", &x,&y);
    		ad(x,y); ad(y,x);
    	}
    	dfs(s,0,1);
    	for(int k=1;k<=20;++k)
    		for(int i=1;i+(1<<k)-1<=tot; ++i)
    			st[k][i] = calc(st[k-1][i], st[k-1][i+(1<<(k-1))]);
    	for(int i=1; i<=m; ++i) {
    		int x,y; scanf("%d%d", &x,&y);
    		cout << lca(x,y) << '
    ';
    	}
    	return 0;
    }
    
  • 相关阅读:
    随机森林算法参数调优
    BAYES和朴素BAYES
    阿里云 金融接口 token PHP
    PHP mysql 按时间分组 表格table 跨度 rowspan
    MySql按周,按月,按日分组统计数据
    PHP 获取今日、昨日、本周、上周、本月的等等常用的起始时间戳和结束时间戳的时间处理类
    thinkphp5 tp5 会话控制 session 登录 退出 检查检验登录 判断是否应该跳转到上次url
    微信 模板消息
    php 腾讯 地图 api 计算 坐标 两点 距离 微信 网页 WebService API
    php添加http头禁止浏览器缓存
  • 原文地址:https://www.cnblogs.com/tztqwq/p/12784679.html
Copyright © 2011-2022 走看看