Khám Phá Bài Toán Tổ Tiên Chung Gần Nhất (LCA)

Chuyên khảo toán học phân tích Skkn chuyên đề bài toán tổ tiên chung gần nhất lca, đánh giá các khía cạnh quan trọng, đề xuất hướng nghiên cứu tiếp theo.

Trường đại học

Trường THPT Chuyên tỉnh Lào Cai

Chuyên ngành

Tin học

Người đăng

Ẩn danh

Thể loại

chuyên đề

2020

57
1
0

Phí lưu trữ

30 Point

Mục lục chi tiết

1.1. Bảng chú thích một số tên, thuật ngữ viết tắt

1.2. Một số khái niệm, kiến thức cơ bản

1.3. Dạng bài toán nào có thể cần đến LCA

1.4. Các phương pháp giải bài toán LCA

1.5. Duyệt tham lam

1.6. Kĩ thuật bảng thưa (Sparse table)

1.7. Dùng Euler tour

1.8. Xử lí kiểu Off-line (Tarjan's off-line LCA)

1.9. Một số bài tập ví dụ

1.9.1. Bài 1: Bài tập cơ bản

1.9.2. Phân tích đề bài và đề xuất thuật toán

1.9.3. Test kèm theo

1.9.4. Bài 2: Tổ chức thi chạy Marathon

1.9.5. Phân tích đề bài và đề xuất thuật toán

1.9.6. Test kèm theo

1.9.7. Bài 3: Du lịch thành phố (NAIPC 2016)

1.9.8. Phân tích đề bài và đề xuất thuật toán

1.9.9. Test kèm theo

1.9.10. Bài 5: Tăng lương (Chọn đội tuyển IOI CROATIAN 2010)

1.9.11. Phân tích đề bài và đề xuất thuật toán

1.9.12. Test kèm theo

1.9.13. Bài 6: Nâng cấp mạng (VOI 2011)

1.9.14. Phân tích đề bài và đề xuất thuật toán

1.9.15. Test kèm theo

1.9.16. Bài 7: Dạo chơi đồng cỏ (PWALK – Spoj)

1.9.17. Phân tích đề bài và đề xuất thuật toán

1.9.18. Test kèm theo

1.9.19. Bài 9: Đường đi qua K cạnh

1.9.20. Phân tích đề bài và đề xuất thuật toán

1.9.21. Test kèm theo

1.9.22. Bài 10: Tom & Jerry

1.9.23. Phân tích đề bài và đề xuất thuật toán

1.9.24. Test kèm theo

1.9.25. Bài 11: Cập nhật thông tin trên cây 1

1.9.26. Đề bài: Update tree

1.9.27. Phân tích đề bài và đề xuất thuật toán

1.9.28. Test kèm theo

1.9.29. Bài 12: Cập nhật thông tin trên cây 2

1.9.30. Đề bài: Update tree2

1.9.31. Phân tích đề bài và đề xuất thuật toán

1.9.32. Test kèm theo

1.9.33. Bài 13: Dạo chơi trên cây

1.9.34. Phân tích đề bài và đề xuất thuật toán

1.9.35. Test kèm theo

1.9.36. Bài 14: Cây đổi gốc

1.9.37. Phân tích đề bài và đề xuất thuật toán

1.9.38. Test kèm theo

1.9.39. Bài 15: Cây đổi gốc 2

1.9.40. Phân tích đề bài và đề xuất thuật toán

1.9.41. Test kèm theo

1.9.42. Một số bài tập tự luyện

1.9.43. Tài liệu tham khảo

Tóm tắt

I. Khái niệm và Định nghĩa LCA

Chuyên đề này tập trung vào giải thuật LCA (Lowest Common Ancestor - Tổ tiên chung gần nhất). LCA của hai đỉnh u và v trên một cây là đỉnh w xa gốc nhất mà cả u và v đều là con cháu của w. Bài toán tìm LCA rất phổ biến trong tin học, đặc biệt trong xử lý dữ liệu dạng cây. Hiểu rõ khái niệm LCA là nền tảng để hiểu các thuật toán giải quyết bài toán này. Giải thuật tìm LCA có nhiều ứng dụng thực tiễn, từ sinh học đến mạng máy tính.

1.1. Khái niệm Tổ tiên chung gần nhất LCA

Tổ tiên chung gần nhất (LCA) được định nghĩa trên cây. Cho hai nút bất kỳ trên cây, LCA là nút tổ tiên chung có độ sâu lớn nhất (xa gốc nhất). Đây là một khái niệm cơ bản trong lý thuyết đồ thị. Việc hiểu rõ khái niệm LCA giúp giải quyết nhiều bài toán phức tạp liên quan đến cấu trúc cây. Thuật toán tìm LCA được ứng dụng rộng rãi trong nhiều lĩnh vực, chẳng hạn như sinh học (phân tích cây phát sinh loài) và mạng máy tính (tìm đường đi ngắn nhất). Tìm hiểu kỹ thuật tìm LCA giúp nâng cao khả năng giải quyết bài toán trên cây. Một số thuật toán phổ biến bao gồm thuật toán Tarjan, thuật toán Binary Lifting, và thuật toán sử dụng Euler Tour.

1.2. Ứng dụng của LCA

LCA có nhiều ứng dụng trong sinh học, cụ thể là trong việc xây dựng và phân tích cây phát sinh loài. Trong mạng máy tính, LCA giúp xác định đường đi ngắn nhất giữa hai nút trong một cây hoặc đồ thị. LCA còn được sử dụng trong các bài toán liên quan đến tìm kiếm, cập nhật thông tin trên cây. Hiểu rõ các ứng dụng của LCA giúp đánh giá được tầm quan trọng của bài toán này. Nắm vững các thuật toán tìm LCA là kỹ năng cần thiết cho sinh viên chuyên ngành tin học. LCA đóng vai trò quan trọng trong việc tối ưu hóa thuật toán xử lý dữ liệu trên cây.

II. Các Phương pháp Giải Thuật Tìm Tổ Tiên Chung Gần Nhất LCA

Có nhiều phương pháp tìm LCA, mỗi phương pháp có độ phức tạp thời gian và không gian khác nhau. Thuật toán LCA tham lam có độ phức tạp O(N) cho mỗi truy vấn, không hiệu quả với nhiều truy vấn. Thuật toán Binary Lifting sử dụng bảng thưa (sparse table), giảm độ phức tạp xuống O(logN) cho mỗi truy vấn. Thuật toán Tarjanphương pháp offline, hiệu quả với nhiều truy vấn, độ phức tạp gần tuyến tính.

2.1. Thuật toán LCA tham lam

Thuật toán LCA tham lam là phương pháp đơn giản nhất. Tuy nhiên, độ phức tạp thời gian của nó là O(N) cho mỗi truy vấn, rất chậm với số lượng truy vấn lớn. Phương pháp này phù hợp với các bài toán có số lượng truy vấn nhỏ. Nó hoạt động bằng cách đi lên từ hai nút cho đến khi gặp nhau tại LCA. Thuật toán tham lam không hiệu quả khi cần xử lý nhiều truy vấn trên cây lớn. Việc tìm hiểu thuật toán tham lam giúp hiểu rõ hơn về cơ chế tìm LCA.

2.2. Thuật toán Binary Lifting

Thuật toán Binary Lifting sử dụng bảng thưa (Sparse Table) để tiền xử lý cây. Độ phức tạp thời gian của nó là O(NlogN) cho tiền xử lý và O(logN) cho mỗi truy vấn. Phương pháp này hiệu quả hơn nhiều so với thuật toán tham lam khi có nhiều truy vấn. Binary Lifting dựa trên việc biểu diễn nhị phân của khoảng cách giữa hai nút. Thuật toán Binary Lifting là một kỹ thuật quan trọng trong xử lý dữ liệu trên cây, thường được sử dụng để giải quyết các bài toán liên quan đến LCARMQ (Range Minimum Query).

2.3. Thuật toán Tarjan Offline LCA

Thuật toán Tarjan là một phương pháp offline để tìm LCA. Nó sử dụng cấu trúc dữ liệu DSU (Disjoint Set Union) và có độ phức tạp thời gian gần tuyến tính. Phương pháp này rất hiệu quả khi có rất nhiều truy vấn. Thuật toán Tarjan dựa trên việc duyệt cây theo chiều sâu và cập nhật tập hợp không giao nhau. Thuật toán Tarjan là một trong những thuật toán LCA hiệu quả nhất, đặc biệt phù hợp với các bài toán có số lượng truy vấn lớn.

III. Phân tích Độ Phức Tạp và So Sánh Các Thuật Toán LCA

So sánh các thuật toán LCA dựa trên độ phức tạp thời gian và không gian. Thuật toán tham lam có độ phức tạp cao nhất, không phù hợp với các bài toán có nhiều truy vấn. Thuật toán Binary LiftingThuật toán Tarjan có độ phức tạp thấp hơn, hiệu quả hơn với nhiều truy vấn. Lựa chọn thuật toán phù hợp phụ thuộc vào số lượng nút và truy vấn của bài toán.

3.1. Độ phức tạp thời gian

Độ phức tạp thời gian của các thuật toán LCA khác nhau. Thuật toán tham lam có độ phức tạp O(N) cho mỗi truy vấn. Thuật toán Binary Lifting có độ phức tạp O(NlogN) cho tiền xử lý và O(logN) cho mỗi truy vấn. Thuật toán Tarjan có độ phức tạp gần tuyến tính. Chọn thuật toán dựa trên độ phức tạp thời gian phù hợp với quy mô dữ liệu. Phân tích độ phức tạp giúp tối ưu hóa hiệu suất thuật toán.

3.2. Độ phức tạp không gian

Độ phức tạp không gian của các thuật toán LCA cũng cần được xem xét. Thuật toán tham lam sử dụng không gian nhỏ. Thuật toán Binary Lifting cần không gian để lưu trữ bảng thưa. Thuật toán Tarjan sử dụng không gian cho cấu trúc dữ liệu DSU. Lựa chọn thuật toán cần cân nhắc cả độ phức tạp thời giankhông gian. Phân tích độ phức tạp không gian giúp chọn thuật toán phù hợp với bộ nhớ khả dụng.

IV. Cài Đặt Thuật Toán LCA bằng C Python và Java

Bài toán LCA có thể được cài đặt bằng nhiều ngôn ngữ lập trình khác nhau như C++, Python và Java. Cài đặt bằng C++ thường hiệu quả hơn về mặt tốc độ. Python có ưu điểm về tính dễ đọc và dễ viết. Java cũng là một lựa chọn tốt với tính khả chuyển cao. Lựa chọn ngôn ngữ lập trình phù hợp phụ thuộc vào yêu cầu của bài toán và kinh nghiệm của người lập trình.

4.1. Cài đặt bằng C

Cài đặt thuật toán LCA bằng C++ cho phép tối ưu hóa hiệu suất. C++ có khả năng xử lý dữ liệu nhanh hơn so với Python và Java. Viết code C++ cần chú ý đến việc quản lý bộ nhớ để tránh rò rỉ bộ nhớ. Cài đặt bằng C++ thường được ưu tiên trong các cuộc thi lập trình. Hiểu rõ cú pháp C++ là điều kiện cần thiết để cài đặt thuật toán LCA hiệu quả.

4.2. Cài đặt bằng Python

Python là ngôn ngữ lập trình dễ học và dễ viết, thuận tiện cho việc cài đặt và kiểm tra thuật toán LCA. Tuy nhiên, tốc độ thực thi của Python thường chậm hơn so với C++. Python có nhiều thư viện hỗ trợ lập trình, giúp rút ngắn thời gian phát triển. Cài đặt bằng Python phù hợp cho việc prototype và kiểm tra thuật toán. Sử dụng Python giúp tăng tốc độ phát triển phần mềm.

4.3. Cài đặt bằng Java

Java là ngôn ngữ lập trình hướng đối tượng, cho phép cài đặt thuật toán LCA một cách có cấu trúc. Java có tính khả chuyển cao, code Java có thể chạy trên nhiều nền tảng khác nhau. Java cũng hỗ trợ lập trình đa luồng, giúp tối ưu hóa hiệu suất trong một số trường hợp. Cài đặt bằng Java phù hợp với các dự án lớn đòi hỏi tính ổn định và khả chuyển cao. Java là lựa chọn tốt cho các ứng dụng doanh nghiệp.

31/01/2025

Trích đoạn nội dung tài liệu

Mở đầu Dạng bài về “Tổ tiên chung gần nhất” cũng khá phổ biến, đây đều là các dạng bài không dễ, đòi hỏi học sinh có tư duy khá, nhiều bài đòi hỏi học sinh sáng tạo mới vận dụng được. Học sinh cần có một số kiến thức để đảm bảo học được chuyên đề này là: cơ bản về phương pháp Quy hoạch động trên cây; Đồ thị cơ bản, duyệt đồ thị; kĩ thuật bảng thưa (Sparse table), cấu trúc dữ liệu (Segment tree, BIT, DSU). Trong quá trình dạy đội tuyển lớp HSG lớp 11, đội tuyển HSG Quốc gia. Từ các bài toán dạng này, cũng cho học sinh ôn lại các kiến thức liên quan khác để giải bài toán LCA như: cấu trúc dữ liệu sparse table, segment tree,…; ôn lại bài toán RMQ; kĩ thuật Heavy light decomposition; kĩ thuật duỗi cây thành mảng (Euler tour); duyệt đồ thị; Quy hoạch động trên cây;… 2.

Một số khái niệm, kiến thức cơ bản - Cây DFS: Quá trình duyệt đồ thị theo chiều sâu (DFS) bắt đầu từ đỉnh 𝑠 cho ta một cây DFS gốc 𝑠. - Quan hệ cha-con trên cây DFS: Khi duyệt DFS, nếu từ đỉnh 𝑢 ta gọi hàm tới thăm đỉnh 𝑣 thì đỉnh 𝑢 là đỉnh cha đỉnh 𝑣. Ví dụ: Đỉnh 1 là cha của các đỉnh 2,3,4. Đỉnh 12,13 là con của đỉnh 10.

- Quan hệ tổ tiên-con cháu: Được định nghĩa đệ quy như sau: + Đỉnh 𝑢 là tổ tiên của chính nó. + Đỉnh cha của đỉnh 𝑢 là tổ tiên của đỉnh 𝑢. + Cha của tổ tiên của 𝑢 cũng là tổ tiên của 𝑢. Ta thấy, đỉnh 𝑢 là tổ tiên của tất cả các đỉnh trong nhánh cây DFS gốc 𝑢.

Ví dụ: Đỉnh 7 là tổ tiên của các đỉnh 7,10,11,12,13 và cả chính nó. Đỉnh 6 là tổ tiên của đỉnh 6,8,9. - Độ sâu: Là khoảng cách đến đỉnh gốc (được tính bằng số đỉnh, hoặc số cạnh, không phải là trọng số của cạnh). Đỉnh gốc của cây DFS quy ước độ sâu là 1.

Ví dụ: Đỉnh 3 có độ sâu là 2; đỉnh 12,13 có độ sâu là 5. - Tổ tiên chung: Đỉnh 𝑤 là tổ tiên của đỉnh 𝑢 và 𝑣 thì 𝑤 được gọi là tổ tiên chung của 𝑢 và 𝑣. Ví dụ: Đỉnh 3 là tổ tiên chung của đỉnh 12 và đỉnh 13. - Định nghĩa tổ tiên chung gần nhất (LCA) trên wiki: Trong lý thuyết đồ thị và khoa học máy tính, LCA của 2 đỉnh 𝑢, 𝑣 trên cây hoặc đồ thị có hướng không chu trình (DAG) gốc 𝑇 là đỉnh 𝑤 sâu nhất (hay đỉnh xa gốc nhất) mà nhận cả 𝑢, 𝑣 làm con cháu, chúng ta coi một đỉnh cũng chính là tổ tiên của chính nó.

Ví dụ: Đỉnh 3 là tổ tiên chung gần nhất của đỉnh 7 và 9. Đỉnh 10 là tổ tiên chung gần nhất của 12,13. Trang 5 skkn Chuyên đề Hội thảo khoa học các trường THPT Chuyên khu vực Duyên Hải và ĐBBB 2020 - Nhận xét thấy 𝐿𝐶𝐴(𝑢, 𝑣) là đỉnh đầu tiên gặp nhau của đường đi từ 𝑢 về gốc và đường đi từ 𝑣 về gốc. Từ nhận xét này ta sẽ hình thành các cách giải bài toán LCA.

Dạng bài toán nào có thể cần đến LCA Trong chuyên đề này, tôi tập trung vào các dạng bài sau: - Các bài tập về tìm kiếm, cập nhật thông tin của các đỉnh nằm trên đường đi đơn từ 𝑢 đến 𝑣. Ví dụ như tính khoảng cách giữa các cặp đỉnh trên cây (cây có trọng số, không có trọng số). - Dạng bài LCA kết hợp cấu trúc dữ liệu như: Segment tree, Binay index tree, Disjoint set union,…. - Dạng bài LCA kết hợp với quy hoạch động trên cây, cây khung, cầu-khớp,… - Dạng bài LCA có đổi gốc.

- Đánh dấu, cộng dồn trên cây có áp dụng LCA. Theo nhận định của tác giả thì các dạng bài khó sẽ là dạng bài phải biết kết hợp thêm các dạng bài khác về cây, kết hợp cấu trúc dữ liệu; các bài cần học sinh có sự sáng tạo mới phát hiện ra cần áp dụng dạng bài toán LCA như thế nào,… 4. Các phương pháp giải bài toán LCA Để trình bày một số phương pháp giải bài toán LCA, tác giả đưa ra ví dụ cây có gốc là 1 như dữ liệu cho sau: Dữ liệu vào Kết quả ra Giải thích 13 lca(2,4)=1 12 lca(12,13)=10 13 lca(2,5)=1 14 lca(8,9)=6 35 lca(12,11)=7 36 lca(6,7)=3 37 68 69 7 10 7 11 10 12 10 13 6 24 Cho đồ thị gồm 13 đỉnh, 12 12 13 cạnh, và 6 câu hỏi truy vấn tìm 25 LCA. 89 12 11 67 Trang 6 skkn Chuyên đề Hội thảo khoa học các trường THPT Chuyên khu vực Duyên Hải và ĐBBB 2020 4.

Duyệt tham lam Nhận xét rằng để tìm tổ tiên chung gần nhất của 2 đỉnh 𝑢, 𝑣 thì từ 2 đỉnh này, ta đi lên từng bước một về phía gốc cây. Đến vị trí gặp nhau đầu tiên thì đó chính là tổ tiên chung gần nhất. Phương pháp: Bước 1: Di chuyển đỉnh có độ sâu lớn hơn đến khi 2 đỉnh có cùng độ sâu. Bước 2: Nếu 2 đỉnh chưa gặp nhau thì ta cùng di chuyển chúng đến khi gặp nhau thì lập tức dừng lại, đó chính là LCA của chúng.

Các làm này khá lâu nếu trong trường hợp cây DFS suy biến thành dạng đường thẳng. Đánh giá độ phức tạp của thuật toán: - Độ phức tạp tiền xử lí (duyệt DFS): 𝑶(𝑵). - Độ phức tạp của một truy vấn là: 𝑶(𝑵).  Độ phức tạp thuật toán chung: 𝑶(𝑵 ∗ 𝑸).

Chương trình tham khảo: #include <bits/stdc++.h> using namespace std; int n, q, par[100005], depth[100005]; vector<int> adj[100005]; ///duyet DFS de xac dinh do xau va tim cha cua cac dinh void dfs(int u, int p, int d) { depth[u] = d; par[u] = p; for(int v : adj[u]) { if(par[u] == v) continue; dfs(v, u, d + 1); } } int lca(int u, int v) { ///Tim LCA theo kieu Brute force if(depth[u] < depth[v]) swap(u, v); while(depth[u] > depth[v]) u = par[u]; while(u != v) { u = par[u]; v = par[v]; } return u; } int main() { cin >> n; for(int i = 1; i < n; i++) { int u, v; cin >> u >> v; adj[u]. Chia căn Nhận xét rằng cách làm Brute Force trên khá lâu vì mỗi lần ta chỉ đi lên được một đỉnh. Trong cách làm sau đây, ta tiền xử lí bằng cách chia cây có độ cao depth[u ]  1 H thành các √𝐻 tầng. Đỉnh có độ sâu 𝑑𝑒𝑝𝑡ℎ[𝑢] thì được xếp vào tầng.

Khi đó nếu 𝑢, 𝑣 chưa cùng tầng thì ta nhảy theo tầng, nếu cùng tầng thì ta nhảy theo cha của nó để đến khi gặp nhau. Đánh giá độ phức tạp của thuật toán: - Độ phức tạp tiền xử lí: 𝑶(𝑵 ∗ √𝑵 ). - Độ phức tạp của một truy vấn là: 𝑶(√𝑵 ).  Độ phức tạp thuật toán chung: 𝑶(𝑵 ∗ √𝑵 + 𝑸 ∗ √𝑵 ).

Ví dụ: H=5 và [√𝐻] = 2 Tầng 1 Tầng 2 Tầng 3 Chương trình tham khảo: #include <bits/stdc++.h> using namespace std; int n, q, H, s, par[100005], depth[100005], T[100005]; vector<int> adj[100005]; ///duyet DFS de xac dinh do xau va tim cha cua cac dinh void dfs0(int u, int p, int d) { depth[u] = d; H = max(H, d); par[u] = p; for(int v : adj[u]) { if(par[u] == v) Trang 8 skkn Chuyên đề Hội thảo khoa học các trường THPT Chuyên khu vực Duyên Hải và ĐBBB 2020 continue; dfs0(v, u, d + 1); } } void dfs(int u, int p, int d) { ///tim to tien o tang tren cua u depth[u] = d; par[u] = p; if(depth[u] < s) T[u] = 1; else if((depth[u] + 1) % s) T[u] = T[par[u]]; else T[u] = par[u]; for(int v : adj[u]) { if(par[u] == v) continue; dfs(v, u, d + 1); } } int lca(int u, int v) { ///Tim LCA chia can while(T[u] != T[v]) if(depth[u] > depth[v]) u = T[u]; else v = T[v]; while(u != v) { if(depth[u] > depth[v]) u = par[u]; else v = par[v]; } return u; } int main() { //freopen("LCA_sqrt.inp", "r", stdin); cin >> n; for(int i = 1; i < n; i++) { int u, v; cin >> u >> v; adj[u].push_back(u); } dfs0(1, 0, 1); s = sqrt(H); dfs(1, 0, 1); cin >> q; while(q--) { int u, v; cin >> u >> v; cout << "lca(" << u << "," << v << ")=" << lca(u, v) << "\n"; } } Trang 9 skkn Chuyên đề Hội thảo khoa học các trường THPT Chuyên khu vực Duyên Hải và ĐBBB 2020 4. Kĩ thuật bảng thưa (Sparse table) Đây là kĩ thuật hay dùng nhất trong giải các bài toán về LCA. Nhận xét rằng mọi số nguyên dương đều có thể biểu dưới dạng nhị phân. Nhận xét này khá quan trọng, từ đó ta có thể cải tiến cách làm của các thuật toán đã giới thiệu ở trên bằng cách nhảy lên các lũy thừa của 2 (binary lifting), từ đó việc tìm 𝐿𝐶𝐴(𝑢, 𝑣) chỉ có độ phức tạp 𝑂(log(𝑁)).

20 Khi đó để 𝑢 nhảy lên tổ tiên 𝑣 trên nó 5 bậc thì ta nhảy đến cha trước đó 22 bậc, sau đó nhảy tiếp cha 20 bậc. Ta sẽ sử dụng bảng thưa (Sparse table), cha thứ 2 𝑗 của đỉnh 𝑖 là 𝑇[𝑖][𝑗]. Định nghĩa Sparse table theo công thức truy hồi như sau: 𝑇[𝑢][0] = 𝑝𝑎𝑟[𝑢] Cha cấp 20 { 𝑇[𝑢][𝑖] = 𝑇[𝑇[𝑢][𝑖 − 1]][𝑖 − 1] Cha cấp 2𝑖 (Vì 2𝑖 = 2𝑖−1 + 2𝑖−1 ) Đánh giá độ phức tạp của thuật toán: - Độ phức tạp tiền xử lí (xây dựng bảng thưa) : 𝑶(𝑵 ∗ 𝒍𝒐𝒈(𝑵)) - Độ phức tạp của một truy vấn là: 𝑶(𝒍𝒐𝒈(𝑵)).  Độ phức tạp thuật toán chung: 𝑶(𝑵 ∗ 𝒍𝒐𝒈(𝑵) + 𝑸 ∗ 𝒍𝒐𝒈(𝑵)).

Chương trình tham khảo: #include <bits/stdc++.h> using namespace std; int n, q, depth[100005], T[100005][17]; vector<int> adj[100005]; void dfs(int u, int p) { ///tim to tien o tang tren cua u depth[u] = depth[p] + 1; T[u][0] = p; for(int i = 1; i < 17; i++) T[u][i] = T[T[u][i - 1]][i - 1]; for(int v : adj[u]) { if(v == p) continue; dfs(v, u); } } int lca(int u, int v) { ///Tim LCA Sparse Table if(depth[u] < depth[v]) swap(u, v); for(int i = 16; i >= 0; i--) ///nhay den cung do sau if(depth[T[u][i]] >= depth[v]) u = T[u][i]; if(u == v) return u; for(int i = 16; i >= 0; i--)///nhay den LCA if(T[u][i] != T[v][i]) { u = T[u][i]; v = T[v][i]; Trang 10 skkn Chuyên đề Hội thảo khoa học các trường THPT Chuyên khu vực Duyên Hải và ĐBBB 2020 } return T[u][0]; } int main() { cin >> n; for(int i = 1; i < n; i++) { int u, v; cin >> u >> v; adj[u].

Nội dung được bảo vệ bản quyền — Tải xuống đầy đủ

Bài viết "Giải Bài Toán Tổ Tiên Chung Gần Nhất (LCA)" cung cấp cái nhìn sâu sắc về một trong những vấn đề quan trọng trong lĩnh vực cấu trúc dữ liệu và thuật toán. Tác giả giải thích rõ ràng về khái niệm LCA, cách thức hoạt động của nó, cũng như các ứng dụng thực tiễn trong việc tối ưu hóa tìm kiếm trong cây nhị phân. Độc giả sẽ được trang bị kiến thức cần thiết để áp dụng LCA vào các bài toán phức tạp hơn, từ đó nâng cao khả năng giải quyết vấn đề trong lập trình và phát triển phần mềm.

Nếu bạn muốn mở rộng thêm kiến thức về các thuật toán và ứng dụng trong lập trình, hãy tham khảo bài viết Tiểu luận thảo luận nhóm tmu bản báo cáo tổng hợp học phần toán cao cấp 2 nhiệm vụ sử dụng python để giải các bài toán, nơi bạn có thể tìm hiểu cách sử dụng Python để giải quyết các bài toán toán học phức tạp. Ngoài ra, bài viết Luận văn thạc sĩ tìm hiểu một số giải thuật tìm kiếm chuỗi con và ứng dụng sẽ giúp bạn khám phá thêm về các thuật toán tìm kiếm, một phần quan trọng trong lập trình. Cuối cùng, bài viết Skkn chuyên đề dfs và ứng dụng sẽ cung cấp cho bạn cái nhìn sâu sắc về thuật toán tìm kiếm theo chiều sâu, một kỹ thuật hữu ích trong nhiều bài toán lập trình.

Những tài liệu này không chỉ giúp bạn củng cố kiến thức mà còn mở ra nhiều cơ hội để áp dụng vào thực tiễn.