LCA[倍增][树剖][tarjan]

LCA:最近公共祖先

倍增:

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<vector>
 5 using namespace std;
 6 #define N 105
 7 int deep[N],dad[N][21];
 8 vector<int>vec[N];
 9 int lca(int x,int y) {
10     if(deep[x]>deep[y])swap(x,y);
11     for(int i=20;i>=0;i--)
12         if(deep[dad[y][i]]>=deep[x])y=dad[y][i];
13     if(x==y)return x;
14     for(int i=20;i>=0;i--)
15         if(dad[x][i]!=dad[y][i])x=dad[x][i],y=dad[y][i];
16     return dad[x][0];
17 }
18 void dfs(int x) {
19     deep[x]=deep[dad[x][0]]+1;
20     for(int i=0;dad[x][i];i++)
21         dad[x][i+1]=dad[dad[x][i]][i];
22     for(int i=0;i<vec[x].size();i++)
23         if(!deep[vec[x][i]])dad[vec[x][i]][0]=x,dfs(vec[x][i]);
24 }
25 int main() {
26     int n,Q,u,v,x,y;
27     scanf("%d",&n);
28     for(int i=1;i<n;i++) {
29         scanf("%d%d",&u,&v);
30         vec[u].push_back(v);
31         vec[v].push_back(u);
32     }
33     dfs(1);
34     scanf("%d",&Q);
35     while(Q--) {
36         scanf("%d%d",&x,&y);
37         printf("%d\n",lca(x,y));
38     }
39     return 0;
40 }

树剖:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<vector>
 5 using namespace std;
 6 #define N 105
 7 int deep[N],top[N],dad[N],size[N];
 8 vector<int>vec[N];
 9 void dfs(int x) {
10     size[x]=1;deep[x]=deep[dad[x]]+1;
11     for(int i=0;i<vec[x].size();i++)
12         if(vec[x][i]!=dad[x]) {
13             dad[vec[x][i]]=x;
14             dfs(vec[x][i]);
15             size[x]+=size[vec[x][i]];
16         }
17 }
18 void dfs1(int x) {
19     int t=0;if(!top[x])top[x]=x;
20     for(int i=0;i<vec[x].size();i++)
21         if(vec[x][i]!=dad[x]&&size[vec[x][i]]>size[t])t=vec[x][i];
22     if(t)top[t]=top[x],dfs1(t);
23     for(int i=0;i<vec[x].size();i++)
24         if(vec[x][i]!=dad[x]&&vec[x][i]!=t)dfs1(vec[x][i]);
25 }
26 int lca(int x,int y) {
27     while(top[x]!=top[y]) {
28         if(deep[top[x]]<deep[top[y]])swap(x,y);
29         x=dad[x];
30     }
31     if(deep[x]>deep[y])swap(x,y);
32     return x;
33 }
34 int main() {
35     int n,u,v,Q,x,y;
36     scanf("%d",&n);
37     for(int i=1;i<n;i++) {
38         scanf("%d%d",&u,&v);
39         vec[u].push_back(v);
40         vec[v].push_back(u);
41     }
42     dfs(1);
43     dfs1(1);
44     scanf("%d",&Q);
45     while(Q--) {
46         scanf("%d%d",&x,&y);
47         printf("%d\n",lca(x,y));
48     }
49     return 0;
50 }

tarjan

 1 #include<cstdio>
 2 #include<vector>
 3 using namespace std;
 4 #define N 1105
 5 int fa[N],qx[N],qy[N],ans[N],dad[N],x,y;
 6 vector<int>vec[N],que[N];
 7 int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
 8 int dfs(int x) {
 9     fa[x]=x;
10     for(int i=0;i<vec[x].size();i++)
11         if(dad[x]!=vec[x][i])
12             dad[vec[x][i]]=x,dfs(vec[x][i]);
13     for(int i=0;i<que[x].size();i++)
14         if(dad[y=qx[que[x][i]]^qy[que[x][i]]^x])
15             ans[que[x][i]]=find(y);
16     fa[x]=dad[x];
17 }
18 int main() {
19     int n,m;
20     scanf("%d%d",&n,&m);
21     for(int i=1;i<n;i++) {
22         scanf("%d%d",&x,&y);
23         vec[x].push_back(y);
24         vec[y].push_back(x);
25     }
26     for(int i=1;i<=m;i++) {
27         scanf("%d%d",&qx[i],&qy[i]);
28         que[qx[i]].push_back(i);
29         que[qy[i]].push_back(i);
30     }
31     dfs(1);
32     for(int i=1;i<=m;i++)
33         printf("%d\n",ans[i]);
34     return 0;
35 }

我会补发注释的

时间: 2024-10-13 04:54:53

LCA[倍增][树剖][tarjan]的相关文章

洛谷P4180 [Beijing2010组队]次小生成树Tree(最小生成树,LCT,主席树,倍增LCA,倍增,树链剖分)

洛谷题目传送门 %%%天平巨佬和山楠巨佬%%% 他们的题解 思路分析 具体思路都在两位巨佬的题解中.这题做法挺多的,我就不对每个都详细讲了,泛泛而谈吧. 首先kruskal把最小生成树弄出来,因为要求次小生成树.至于为什么次小一定只在最小的基础上改变了一条边,我也不会证......打表找规律大法好 剩下的可以有一堆数据结构来维护最大值和次大值(原理两位巨佬都讲清楚了,这里只分析一下算法的优劣) 倍增+LCA 山楠巨佬的做法,我也写了这一种.复杂度\(O(MlogM(kruscal)+MlogN(

【BZOJ3626】【LNOI2014】LCA (树剖+离线)

Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)].(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)答案对201314取模. 这个题是大饺子安利给我的,然后顺带学了一发树剖(好弱啊). 这个题解讲的很好啦w:http://www.cnbl

【树剖求LCA】树剖知识点

#include<cstdio> #include<iostream> using namespace std; struct edge{ int to,ne; }e[1000005]; int n,m,s,ecnt,head[500005],dep[500005],siz[500005],son[500005],top[500005],f[500005]; void add(int x,int y) //加边 { e[++ecnt].to=y; e[ecnt].ne=head[x

LCA 倍增||树链剖分

方法1:倍增 1498ms #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> using namespace std; typedef long long ll; const int N=5e5+5; inline int read(){ char c=getchar();int x=0,f=1; while

tarjan,树剖,倍增求lca

1.tarjan求lca Tarjan(u)//marge和find为并查集合并函数和查找函数 { for each(u,v) //访问所有u子节点v { Tarjan(v); //继续往下遍历 marge(u,v); //合并v到u上 标记v被访问过; } for each(u,e) //访问所有和u有询问关系的e { 如果e被访问过; u,e的最近公共祖先为find(e); } } 2.倍增lca(在线) #include<bits/stdc++.h> using namespace st

51nod2621 树上距离一题四解ST表+倍增+Tarjan+树剖

LCA裸题 只有代码无原理,给自己复习用 1. ST表(这题2^10就够了) 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 const int maxn=2e3+50; 5 6 int cnt,dfn[maxn],dep[maxn],dp[maxn][21],lg2[maxn],dis[maxn],w[maxn][maxn]; 7 std::vector<int> G[maxn]; 8 void dfs(int u,in

最近公共祖先(LCA)问题的树剖实现 (模板)

我来存个档,防止忘记!2333 传送门:https://daniu.luogu.org/problem/show?pid=3379 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输

LCA(倍增在线算法) codevs 2370 小机房的树

codevs 2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计

BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树

2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/problem.php?id=2243 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“112221”由3段组成:“11”.“222”和“1”. 请你写