-
Step1 Problem:
[原题] 给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。
-
Step2 Ideas:
lca模板题,主要为了存模板。LCA(Least Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先
-
Step3 Code: Tarjan,离线算法,时间复杂度O(n + q)
1 // luogu-judger-enable-o2 2 #define _CRT_SECURE_NO_WARNINGS 3 #include<cstdio> 4 #include<iostream> 5 #include<cstring> 6 #include<algorithm> 7 #include<bitset> 8 #include<cassert> 9 #include<cctype> 10 #include<math.h> 11 #include<cstdlib> 12 #include<ctime> 13 #include<deque> 14 #include<iomanip> 15 #include<list> 16 #include<map> 17 #include<queue> 18 #include<set> 19 #include<stack> 20 #include<vector> 21 #define lt k<<1 22 #define rt k<<1|1 23 #define lowbit(x) x&(-x) 24 #define lson l,mid,lt 25 #define rson mid+1,r,rt 26 using namespace std; 27 typedef long long ll; 28 typedef long double ld; 29 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 30 #define mem(a, b) memset(a, b, sizeof(a)) 31 //#define int ll 32 const double pi = acos(-1.0); 33 const double eps = 1e-6; 34 const double C = 0.57721566490153286060651209; 35 const ll mod = 3e7; 36 const int inf = 0x3f3f3f3f; 37 const ll INF = 0x3f3f3f3f3f3f3f3f; 38 const int maxn = 5e5+ 4000; 39 struct node { 40 int u, v, w, next; 41 node () {} 42 node(int u_, int v_, int w_, int next_) { 43 u = u_; 44 v = v_; 45 w = w_; 46 next = next_; 47 } 48 } edge[maxn << 1]; 49 50 struct nod { 51 int u, v, id, next; 52 nod() {} 53 nod(int u_, int v_, int id_, int next_) { 54 u = u_; 55 v = v_; 56 id = id_; 57 next = next_; 58 } 59 }qu[maxn << 1]; 60 int n, m, ans; 61 int head[maxn], head1[maxn]; 62 int cnt, cnt1; 63 int res[maxn]; 64 int de[maxn], pre[maxn], fa[maxn]; 65 bool vis[maxn]; 66 67 void init() { 68 cnt = cnt1 = 0; 69 mem(vis, false); 70 mem(de, 0); 71 mem(head, -1); 72 mem(head1, -1); 73 mem(qu, 0); 74 mem(edge, 0); 75 for (int i = 1; i <= n; i++) fa[i] = i; 76 } 77 78 void add_edge(int u, int v, int w) { 79 edge[cnt] = (node){ u, v, w, head[u] }; 80 head[u] = cnt++; 81 } 82 83 void add_qu(int u, int v, int id) { 84 qu[cnt1] = (nod){ u, v, id, head1[u] }; 85 head1[u] = cnt1++; 86 } 87 88 int find_fa(int x) { 89 if (x == fa[x]) return x; 90 else return fa[x] = find_fa(fa[x]); 91 } 92 93 void Tarjan(int u) { 94 vis[u] = true; 95 for (int i = head[u]; ~i; i = edge[i].next) { 96 int v = edge[i].v; 97 if (!vis[v]) { 98 Tarjan(v); 99 int r1 = find_fa(u); 100 int r2 = find_fa(v); 101 if (r1 != r2) fa[r2] = r1; 102 } 103 } 104 for (int i = head1[u]; ~i; i = qu[i].next) { 105 int v = qu[i].v; 106 if (vis[v]) res[qu[i].id] = find_fa(v); 107 } 108 } 109 110 int main() { 111 // freopen("testdata.in", "r", stdin); 112 int s; 113 cin >> n >> m >> s; 114 init(); 115 for (int i = 1; i < n; i++) { 116 int u, v; 117 cin >> u >> v; 118 add_edge(u, v, 1); 119 add_edge(v, u, 1); 120 } 121 for (int i = 1; i <= m; i++) { 122 int a, b; 123 cin >> a >> b; 124 add_qu(a, b, i); 125 add_qu(b, a, i); 126 } 127 Tarjan(s); 128 for (int i = 1; i <= m; i++) cout << res[i] << endl; 129 return 0; 130 }
-
Step4 Code2: 倍增法求lca,在线算法,时间复杂度O(n logn)
1 #define _CRT_SECURE_NO_WARNINGS 2 #include<cstdio> 3 #include<iostream> 4 #include<cstring> 5 #include<algorithm> 6 #include<bitset> 7 #include<cassert> 8 #include<cctype> 9 #include<math.h> 10 #include<cstdlib> 11 #include<ctime> 12 #include<deque> 13 #include<iomanip> 14 #include<list> 15 #include<map> 16 #include<queue> 17 #include<set> 18 #include<stack> 19 #include<vector> 20 #define lt k<<1 21 #define rt k<<1|1 22 #define lowbit(x) x&(-x) 23 #define lson l,mid,lt 24 #define rson mid+1,r,rt 25 using namespace std; 26 typedef long long ll; 27 typedef long double ld; 28 #define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 29 #define mem(a, b) memset(a, b, sizeof(a)) 30 //#define int ll 31 const double pi = acos(-1.0); 32 const double eps = 1e-6; 33 const double C = 0.57721566490153286060651209; 34 const ll mod = 3e7; 35 const int inf = 0x3f3f3f3f; 36 const ll INF = 0x3f3f3f3f3f3f3f3f; 37 const int maxn = 5e5+ 4000; 38 int lg[maxn], dep[maxn], fa[maxn][20], head[maxn]; 39 int cnt; 40 int n, m, s; 41 42 struct node { 43 int v, next; 44 } edge[maxn << 1]; 45 46 void add_edge(int u, int v) { 47 edge[cnt].v = v; 48 edge[cnt].next = head[u]; 49 head[u] = cnt++; 50 } 51 52 void init() { 53 cnt = 0; 54 for (int i = 1; i <= n; i++) { 55 head[i] = -1; 56 dep[i] = -1; 57 lg[i] = lg[i - 1] + (1 << (lg[i - 1]) == i); 58 } 59 mem(fa, 0); 60 } 61 62 void dfs(int u, int fath) { 63 dep[u] = dep[fath] + 1; 64 fa[u][0] = fath; 65 for (int i = 1; (1 << i) <= dep[u]; i++) { 66 fa[u][i] = fa[fa[u][i - 1]][i - 1]; 67 } 68 for (int i = head[u]; ~i; i = edge[i].next) { 69 if (edge[i].v != fath) dfs(edge[i].v, u); 70 } 71 } 72 73 int lca(int u, int v) { 74 if (dep[u] < dep[v]) swap(u, v); 75 while (dep[u] > dep[v]) u = fa[u][lg[dep[u] - dep[v]] - 1]; 76 if (u == v) return u; 77 for (int i = lg[dep[u]] - 1; i >= 0; i--) { 78 if (fa[u][i] != fa[v][i]) { 79 u = fa[u][i]; 80 v = fa[v][i]; 81 } 82 } 83 return fa[u][0]; 84 } 85 86 int main() { 87 scanf("%d%d%d", &n, &m, &s); 88 init(); 89 for (int i = 1; i < n; i++) { 90 int u, v; 91 cin >> u >> v; 92 add_edge(u, v); 93 add_edge(v, u); 94 } 95 dfs(s, 0); 96 for (int i = 1; i <= m; i++) { 97 int u, v; 98 scanf("%d%d", &u, &v); 99 printf("%d ", lca(u, v)); 100 } 101 return 0; 102 }