From 80b6e4fcafa1aee41edacbfdb492c1f2452314fe Mon Sep 17 00:00:00 2001 From: hit_lu Date: Thu, 18 Sep 2025 19:30:23 +0800 Subject: [PATCH] add template and example of binary fitting --- ...e-weight-equilibrium-queries-in-a-tree.cpp | 99 +++++++++++++++++++ binary-lifting/lowest-common-ancestor.cpp | 73 ++++++++++++++ binary-lifting/tree-binary-lifting.cpp | 40 ++++++++ 3 files changed, 212 insertions(+) create mode 100644 binary-lifting/2846. minimum-edge-weight-equilibrium-queries-in-a-tree.cpp create mode 100644 binary-lifting/lowest-common-ancestor.cpp create mode 100644 binary-lifting/tree-binary-lifting.cpp diff --git a/binary-lifting/2846. minimum-edge-weight-equilibrium-queries-in-a-tree.cpp b/binary-lifting/2846. minimum-edge-weight-equilibrium-queries-in-a-tree.cpp new file mode 100644 index 0000000..3b942a7 --- /dev/null +++ b/binary-lifting/2846. minimum-edge-weight-equilibrium-queries-in-a-tree.cpp @@ -0,0 +1,99 @@ +/* There is an undirected tree with n nodes labeled from 0 to n - 1. You are given the integer n and a 2D integer array edges of length n - 1, where edges[i] = [ui, vi, wi] indicates that there is an edge between nodes ui and vi with weight wi in the tree. + + You are also given a 2D integer array queries of length m, where queries[i] = [ai, bi]. For each query, find the minimum number of operations required to make the weight of every edge on the path from ai to bi equal. In one operation, you can choose any edge of the tree and change its weight to any value. + + Note that: + + Queries are independent of each other, meaning that the tree returns to its initial state on each new query. + The path from ai to bi is a sequence of distinct nodes starting with node ai and ending with node bi such that every two adjacent nodes in the sequence share an edge in the tree. + Return an array answer of length m where answer[i] is the answer to the ith query. +*/ +#include +#include +#include +#include +#include +using namespace std; + +class Solution { +private: + vector> predecessor; + vector depth; + vector>> counter; +public: + vector minOperationsQueries(int n, vector>& edges, vector>& queries) { + int m = bit_width((unsigned)n); + counter.resize(n, vector>(m)); // counter[k][i][j] -> 从结点k向上跳2^i权重j出现得次数,权重取值范围1~26 + predecessor.resize(n, vector(m, -1)); + depth.resize(n, 0); + + vector>> graph(n); + for (const auto& edge : edges) { + int u = edge[0], v = edge[1], w = edge[2] - 1; + graph[u].emplace_back(v, w); + graph[v].emplace_back(u, w); + } + + auto dfs = [&](auto&& dfs, int x, int fa) -> void { + predecessor[x][0] = fa; + for (auto [y, w] : graph[x]) { + if (y != fa) { + counter[y][0][w] = 1; + depth[y] = depth[x] + 1; + dfs(dfs, y, x); + } + } + }; + dfs(dfs, 0, -1); + + for (int i = 1; i < m; i++) { + for (int x = 0; x < n; x++) { + if (int p = predecessor[x][i - 1]; p != -1) { + predecessor[x][i] = predecessor[p][i - 1]; + for (int j = 0; j < 26; j++) { + counter[x][i][j] = counter[x][i - 1][j] + counter[p][i - 1][j]; + } + } + } + } + + vector ans; + for (auto& query : queries) { + int u = query[0], v = query[1]; + int path_len = depth[u] + depth[v]; + array cur_counter = {0}; + if (depth[u] > depth[v]) { + swap(u, v); + } + + for (int k = depth[v] - depth[u]; k; k &= k - 1) { + int i = countr_zero(unsigned(k)); + int p = predecessor[v][i]; + for (int j = 0; j < 26; j++) { + cur_counter[j] += counter[v][i][j]; + } + v = p; + } + + if (u != v) { + for (int i = m - 1; i >= 0; i--) { + int pu = predecessor[u][i], pv = predecessor[v][i]; + if (pu != pv) { + for (int j = 0; j < 26; j++) { + cur_counter[j] += counter[u][i][j] + counter[v][i][j]; + } + u = pu, v = pv; + } + } + for (int j = 0; j < 26; j++) { + cur_counter[j] += counter[u][0][j] + counter[v][0][j]; + } + u = predecessor[u][0]; + } + + path_len -= depth[u] * 2; + ans.push_back(path_len - ranges::max(cur_counter)); + } + return ans; + } +}; diff --git a/binary-lifting/lowest-common-ancestor.cpp b/binary-lifting/lowest-common-ancestor.cpp new file mode 100644 index 0000000..ed50111 --- /dev/null +++ b/binary-lifting/lowest-common-ancestor.cpp @@ -0,0 +1,73 @@ +#include +#include +#include +#include + +class TreeAncestor { +private: + std::vector> predecessor; + std::vector depth; +public: + TreeAncestor(std::vector>& edges) { + int n = edges.size() + 1; + int m = bit_width((unsigned)n); + predecessor.resize(n, std::vector(m, -1)); + depth.resize(n, 0); + + std::vector> graph(n); + for (const auto& [u, v] : edges) { + graph[u].emplace_back(v); + graph[v].emplace_back(u); + } + + auto dfs = [&](auto&& dfs, int x, int fa) -> void { + predecessor[x][0] = fa; + for (auto y : graph[x]) { + if (y != fa) { + depth[y] = depth[x] + 1; + dfs(dfs, y, x); + } + } + }; + dfs(dfs, 0, -1); + + for (int i = 1; i < m; i++) { + for (int x = 0; x < n; x++) { + if (int p = predecessor[x][i - 1]; p != -1) { + predecessor[x][i] = predecessor[p][i - 1]; + } + } + } + } + + int getKthAncestor(int node, int k) { + //for (int i = 0; i < bit_width((unsigned)k) && node != -1; i++) { + // if (k >> i & 1) { + // node = predecessor[node][i]; + // } + //} + for (; k && node != -1; k &= k - 1) { + node = predecessor[node][countr_zero(unsigned(k))]; + } + return node; + } + int getLowestCommonAncestor(int u, int v) { + if (depth[u] > depth[v]) { + std::swap(u, v); + } + + for (int k = depth[v] - depth[u]; k; k &= k - 1) { + v = predecessor[v][countr_zero(unsigned(k))]; + } + + if (u != v) { + for (int i = predecessor[u].size() -1; i >= 0; i--) { + int pu = predecessor[u][i], pv = predecessor[v][i]; + if (pu != pv) { + u = pu, v = pv; + } + } + } + return predecessor[u][0]; + } +}; \ No newline at end of file diff --git a/binary-lifting/tree-binary-lifting.cpp b/binary-lifting/tree-binary-lifting.cpp new file mode 100644 index 0000000..50453de --- /dev/null +++ b/binary-lifting/tree-binary-lifting.cpp @@ -0,0 +1,40 @@ +/* + Search for the Kth Ancestor of a Tree Node +*/ +#include +#include +#include +#include + +class TreeAncestor { +private: + std::vector> predecessor; + +public: + TreeAncestor(int n, std::vector& parent) { + int m = bit_width((unsigned)n); + predecessor.resize(n, std::vector(m, -1)); + for (int i = 0; i < n; i++) { + predecessor[i][0] = parent[i]; + } + for (int i = 1; i < m; i++) { + for (int x = 0; x < n; x++) { + if (int p = predecessor[x][i - 1]; p != -1) { + predecessor[x][i] = predecessor[p][i - 1]; + } + } + } + } + + int getKthAncestor(int node, int k) { + // for (int i = 0; i < bit_width((unsigned)k) && node != -1; i++) { + // if (k >> i & 1) { + // node = predecessor[node][i]; + // } + // } + for (; k && node != -1; k &= k - 1) { + node = predecessor[node][countr_zero(unsigned(k))]; + } + return node; + } +};