当前位置: 首页 > news >正文

做网站的任务书广州seo推荐

做网站的任务书,广州seo推荐,人才微网站开发,介绍几个免费的网站L C A LCA LCA:树上两个点的最近公共祖先。(两个节点所有公共祖先中,深度最大的公共祖先) L C A LCA LCA的性质: 在所有公共祖先中, L C A ( x , y ) LCA(x,y) LCA(x,y)到 x x x和 y y y的距离都最短。 x …

L C A LCA LCA:树上两个点的最近公共祖先。(两个节点所有公共祖先中,深度最大的公共祖先)

L C A LCA LCA的性质:

  1. 在所有公共祖先中, L C A ( x , y ) LCA(x,y) LCA(x,y) x x x y y y的距离都最短。
  2. x x x y y y之间最短的路径经过 L C A ( x , y ) LCA(x,y) LCA(x,y)
  3. x x x y y y本身也可以是它们自己的公共祖先。若 y y y x x x的祖先,则有 L C A ( x , y ) = y LCA(x,y) = y LCA(x,y)=y
  4. L C A ( x , y , z ) = L C A ( x , L C A ( y , z ) ) LCA(x,y,z) = LCA(x, LCA(y,z)) LCA(x,y,z)=LCA(x,LCA(y,z))
  5. L C A ( x 1 , x 2 , . . . , x n ) = L C A ( d f s 序最大点, d f s 序最小点 ) LCA(x_1, x_2,...,x_n) = LCA(dfs序最大点,dfs序最小点) LCA(x1,x2,...,xn)=LCA(dfs序最大点,dfs序最小点)

本文主要介绍求 L C A LCA LCA的两种方法:倍增法和 T a r j a n Tarjan Tarjan

先引入例题:

【模板】LCA

题目描述

给定一个 n n n个点以结点 1 1 1为根的树,有 q q q次询问,每次询问给出两个点 u , v u,v u,v,求 L C A ( u , v ) LCA(u,v) LCA(u,v)

L C A ( u , v ) LCA(u,v) LCA(u,v)表示 u , v u,v u,v的最近公共祖先。

输入描述

第一行一个整数 n n n表示结点个数。 ( 1 ≤ n ≤ 2 × 1 0 5 ) (1 \leq n \leq 2 \times 10^5) (1n2×105)

第二行 n − 1 n−1 n1个整数,表示 2 ∼ n 2∼n 2n结点的父亲。

第三行一个整数 q q q,表示询问次数。 ( 1 ≤ q ≤ 2 × 1 0 5 ) (1 \leq q \leq 2 \times 10^5) (1q2×105)

接下来 q q q行,每行两个整数 u , v u,v u,v ( 1 ≤ u , v ≤ n ) (1≤u,v≤n) (1u,vn)

输出描述

对于每次询问,一行一个整数表示结果。

输入样例1

5
1 1 2 3
3
1 2
2 4
1 5

输出样例1

1
2
1

倍增法:

大体就是让两个点不断向上走,直到走到最近的相同的点。如何快速地走?这里就需要用倍增法来实现。倍增法的原理利用了二进制的性质:任意一个数字都可以由一个或几个 2 2 2的幂相加得到,所以可以以 1 , 2 , 4 , 8... 1,2,4,8... 1,2,4,8...这种 2 2 2的幂作为一步的长度向上走。

因为我们不知道应该走多大,所以应该先尝试走大数,能走即走,再尝试走小步。

为了快速地进行跳跃,我们需要预处理出一个帮助我们进行跳跃的数组 f a [ N ] [ 20 ] fa[N][20] fa[N][20] f a [ x ] [ i ] fa[x][i] fa[x][i]表示从 x x x出发向上走 2 i 2^{i} 2i步到达的位置)。计算 f a fa fa数组时用到了 d p dp dp的思路,这里有个递推公式: f a [ x ] [ i ] = f a [ f a [ x ] [ i − 1 ] ] [ i − 1 ] fa[x][i] = fa[fa[x][i - 1]][i - 1] fa[x][i]=fa[fa[x][i1]][i1],意思是从点 x x x出发,先跳 2 i − 1 2 ^ {i - 1} 2i1步,再跳 2 i − 1 2 ^ {i - 1} 2i1步。由小推到大。

得到这个数组之后,就可以快速地计算 L C A LCA LCA了。具体步骤如下:

先将点 x x x和点 y y y处理至同一深度。让深度较大的数以祖先链上深度与深度较小的那个点相等的点为目标进行跳跃。特殊的,如果该点就是深度较浅的那个点,则使用上述 L C A LCA LCA的性质中的第三条。

之后,点 x x x和点 y y y再同时向上跳跃。直至分别跳到 L C A ( x , y ) LCA(x,y) LCA(x,y)的两个儿子上。即 x ≠ y x \not = y x=y并且 f a [ x ] [ 0 ] = f a [ y ] [ 0 ] fa[x][0] = fa[y][0] fa[x][0]=fa[y][0]

最后得到的 f a [ x ] [ 0 ] fa[x][0] fa[x][0]就是 L C A ( x , y ) LCA(x,y) LCA(x,y)

时间复杂度为: O ( n l o g 2 n + q l o g 2 n ) O(nlog_2n + qlog_2n) O(nlog2n+qlog2n)

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 9, T = 20;vector<int> g[N];
int fa[N][30], dep[N];void dfs(int x)
{dep[x] = dep[fa[x][0]] + 1;     //预处理各个节点深度//预处理fa数组for(int i = 1; i <= T; ++i) fa[x][i] = fa[fa[x][i - 1]][i - 1];for(const auto &i : g[x]){dfs(i);}
}int lca(int u, int v)
{if(dep[u] < dep[v]) swap(u, v);     //不妨设点u深度大于等于点v//跳跃,先走大步再走小步//将u点跳至于点v相同高度for(int i =  T; i >= 0; --i){if(dep[fa[u][i]] >= dep[v]) u = fa[u][i];}if(u == v) return u;//一起往上跳for(int i = T; i >= 0; --i){if(fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];}return fa[u][0];
}int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int n; cin >> n;for(int i = 2; i <= n; ++i){cin >> fa[i][0];g[fa[i][0]].push_back(i);}dfs(1);int q; cin >> q;while(q--){int u, v; cin >> u >> v;cout << lca(u, v) << '\n';}return 0;
}

Tarjan

大概流程:

还是采用 d f s dfs dfs,访问到一个点的时候,先标记被访问,然后向下处理它的儿子节点,看儿子节点是否为所求 L C A LCA LCA有关的点,处理完儿子节点之后回溯上来时再处理自己,看自己是否为所求 L C A LCA LCA有关的点。再向上合并,合并采用并查集进行合并且使用路径压缩。

因为有多组询问,所以需要将询问离线。

对于一对点中的一个点处理的时候,若另一个点已经被访问过了,那么那个点在的并查集中的根节点就是它们的 L C A LCA LCA,这和 d f s dfs dfs的性质有关。都访问到的时候,它们一定在同一棵子树上,并且这颗子树的根显然就是它们的 L C A LCA LCA

时间复杂度为: O ( n + q ) O(n + q) O(n+q)

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 9;int pre[N], dep[N], ans[N], fa[N];
vector<int> g[N];
vector<pair<int, int>> Q[N];
bitset<N> vis;//并查集基础操作
int find(int x)
{return pre[x] = (pre[x] == x ? x : find(pre[x]));
}void merge(int x, int y)    //将深度大的向深度小的合并,向上合并
{int fx = find(x), fy = find(y);if(dep[fx] < dep[fy]) swap(fx, fy);pre[fx] = fy;
}void dfs(int x)
{//顺手计算深度,合并时使用dep[x] = dep[fa[x]] + 1;vis[x] = true;for(const auto &y : g[x]) dfs(y);   //先处理所有儿子for(const auto &[y, id] : Q[x])     //在处理自己{if(!vis[y]) continue;       //如果对方未被访问就跳过ans[id] = find(y);}merge(x, fa[x]);
}void solve()
{int n; cin >> n;for(int i = 1; i <= n; ++i) pre[i] = i;for(int i = 2; i <= n; ++i){cin >> fa[i];g[fa[i]].push_back(i);}int q; cin >> q;//将询问离线for(int i = 1; i <= q; ++i){int x, y; cin >> x >> y;Q[x].push_back({y, i});Q[y].push_back({x, i});}dfs(1);for(int i = 1; i <= q; ++i) cout << ans[i] << '\n';
}int main()
{ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);int _ = 1;while(_--) solve();return 0;
}

L C A LCA LCA可以求树上两点之间的最短距离,也可以做树上差分,这里就不过多赘述。

http://www.khdw.cn/news/31041.html

相关文章:

  • 免费制作个人网页关键词长尾词优化
  • 做网站 发现对方传销重庆森林为什么不能看
  • 微信网站建设教程手机怎么搭建属于自己的网站
  • 网站建设平台的比较百度搜索资源
  • 二手交易网站建设目标找竞价托管公司
  • 深圳做棋牌网站建设有哪些公司seo需要掌握哪些技术
  • 如何做网站公司seo自学网免费
  • 网站建设与管理 教学设计电脑编程培训学校
  • 用vs做网站好的网站或网页
  • 腾讯网站自己做网络推广怎么做
  • 发帖网站百度收率高的怎样优化网站
  • 阿里云做网站需要环境下载百度网盘
  • 100种迷你小手工好的seo公司营销网
  • 网站开发网页页面跳转合肥最新消息今天
  • 经典网站设计小吴seo博客
  • 国外注册机网站网销怎么销售的
  • 杭州做网站工作室企业网站有哪些功能
  • 怎么做网站的百度收录武汉网站制作推广
  • 做区块链网站的公司关键词优化武汉
  • 对网站建设的认识商品营销推广的方法有哪些
  • 信誉好的广州外贸网站搜索引擎优化怎么做的
  • asp.net网站转php百度账号设置
  • 做本地网站需要的软件百度手机seo
  • 淮安网站建设要多少钱自助建站系统平台
  • 中小企业网站建设案例semir
  • 住房与城乡建设网站北京网站制作建设公司
  • 做网站运营需要做哪些百度安装免费下载
  • 南京做征信服务的公司网站企业网站的作用
  • 中国工信备案查询网站梅花seo 快速排名软件
  • 购物网站要多少钱cnn头条新闻