都加了注释,可以当算法模板使用,注意思考每种方法的适用场景
目录
方法一
struct Binary{
struct Node{
struct Node *left {nullptr};
struct Node *right {nullptr};
int tag;
// different node has differed tag
inline bool operator==(const Node& other) const
{ return tag == other.tag; }
} *root {}; // a tree node definition
// a binary tree must have a root( may be nil root)
//f __lca__ called by f lca, update the answer node pointer
bool __lca__(Node **ans, Node *o, Node *p, Node *q) const{
if(!o) return false;
bool left_flag { __lca__(ans, o->left, p, q) };
bool right_flag { __lca__(ans, o->right, p, q) };
bool condition_one { (*o == *p || *o == *q) && (left_flag || right_flag) };
bool condition_two { left_flag && right_flag };
if( condition_one || condition_two )
// lca of node p and node q must satisfy this condition
// either meet the condition that :
// both left-subtree and right-subtree maintain one of node p or q
// or meet the condition that:
// x is node p or q itself and one of its subtree holds another node to be found
*ans = o;
return condition_one;
}
Node *lca(Node *p, Node *q) const{
if(!root || !p || !q) return nullptr;
//special judge
Node *ans {};
__lca__(&ans, root, p, q);
//pass a double pointer
return ans;
}
};
方法二
struct Binary{
struct Node{
struct Node *left {nullptr};
struct Node *right {nullptr};
int tag;
// tag is to distinguish two differed node
inline bool operator==(const Node& other) const
{ return tag == other.tag; }
//operator== override
} *root {}; // init with a nil root
//tree node definition
std::unordered_map<int, Node *> parent;
//hashmap to record every node's parent
//specially, root's parent is null
void dfs(Node *o){
if(!o) return;
if(o->left) parent[o->left->tag] = o;
if(o->right) parent[o->right->tag] = o;
dfs(o->left);
dfs(o->right);
}
//iterate the whole tree to find nodes' parent
Node *lca(Node *p, Node *q) const{
//special judge
if(!root || !p || !q) return nullptr;
dfs(root);
//update the parent
std::unordered_map<int, bool > visited;
while(p){
visited[p->tag] = true;
p = parent[p->tag];
}
//record the path from p directly to the root
while(q){
//q climbing the root upward until firstly meet the path
// that node q has vistied before
if(visited[q->tag]) return q;
q = parent[q->tag];
}
}
};
方法三
struct Binary{
struct Node{
struct Node *left {nullptr};
struct Node *right {nullptr};
int tag;
//data tag is to represent differed nodes
inline bool operator==(const Node& other) const
{ return tag == other.tag; }
//operator== override by nodes' tag
} *root {}; // bin-tree initialized with a nil root
//treenode definition
std::unordered_map<int, Node *> parent;
//hashmap to record every nodes' parent
//specially, root has a nil parent
void dfs(Node *o){
if(!o) return;
if(o->left) parent[o->left->tag] = o;
if(o->right) parent[o->right->tag] = o;
//dfs to update the parents
dfs(o->left);
dfs(o->right);
}
Node *lca(Node *p, Node *q) const{
if(!root || !p || !q) return nullptr;
dfs(root);
Node *pp { p };
Node *qq { q };
//circularilly loop between root and p|q
// until pp and qq meet
while(*pp == *qq){
pp = pp ? parent[pp->tag] : p;
qq = qq ? parent[qq->tag] : qq;
}
return pp;
}
};
方法四
struct Binary{
struct Node{
struct Node *left {nullptr};
struct Node *right {nullptr};
inline bool operator==(const Node& other) const
{ return tag == other.tag; }
} *root {};
//tree-node definition
std::unordered_map<Node *, Node *> par;
//record the disjoined-set-uinion's parent
std::unordered_map<std::pair<Node *, Node *>, Node *> lca;
//record every quiry's lca result
std::unordered_map<Node *, bool> visited;
//record whether or not a node has been visited
std::vector<Node *> collection;
//push all nodes into a flatted array, then conviniently iterated
void dfs(Node *o){
if(!o) return;
collection.push_back(o);
dfs(o->left);
dfs(o->right);
}
//push nodes into vector
inline Node *find_par(Node *o){
return par[o] == o ? o : (par[o] = find_par(par[o]));
}
//DSU quiry
void tarjan(Node *o){
if(o->left){
par[o->left] = o;
visited[o->left] = true;
//mark the visited flag
// and record nodes' parent
}
if(o->right){
par[o->right] = o;
visited[o->right] = true;
}
auto __size__{ collection.size() };
for(auto i {0U}; i < __size__; ++i)
for(auto j {i + 1U}; j < __size__; ++j){
Node *lhs { collection[i] };
Node *rhs { collection[j] };
Node *p { find_par(o) };
lca[{lhs, rhs}] = lca[{rhs, lhs}] = p;
}
}
//tarjan: take advantage of dfs's time stamp property to handle this algorithm
Node *lca(Node *p, Node *q) const{
if(!root || !p || !q) return nullptr;
//special judge
dfs(root);
//dfs to collect nodes into vector
for(auto o : collection) par[o] = o;
//init DSU set
tarjan(root);
return lca[{p, q}];
}
};
方法五
constexpr std::size_t __MAX_NODES_{ 50001U };
constexpr std::size_t __MAX_EDGES_{ 50000U };
constexpr std::size_t __MAX_DEPTH_{ 1 << 4 | 1 };
typedef struct {
int32_t __forward__; //forward adjacent node
int32_t __next__; //next edge
} edge;
typedef struct {
uint32_t __depth__;
int32_t __ancestor__[__MAX_NODES_];
} node;
int32_t head[__MAX_NODES_];
edge edges[__MAX_EDGES_];
node nodes[__MAX_NODES_];
uint32_t tot {};
void insert(uint32_t u, uint32_t v){
//__COMMENT__: insert a edge from u to v
edges[tot] = edge{ __forward__ : v, __next__ : head[u] };
head[u] = tot ++;
}
inline void __init__(void){
//__COMMENT__: init the head of all edges
std::memset(head, -1, sizeof head);
}
void getDeep(int32_t u,int32_t fa){
//__COMMENT__: dfs to update every node's depth in the tree
// and their levelled-ancestor
if(fa) nodes[u].__depth__ = nodes[fa].__depth__ + 1;
nodes[u].__ancestor__[0] = fa;
for(auto i { 1U }; (1U<<i) < deep[cur]; ++i)
nodes[u].__ancestor__[i] = nodes[nodes[u].__ancestor__[i-1]].__ancestor__[i-1];
//2^i=2^(i-1)+2^(i-1) RMQ DP
for(auto i {head[u]}; ~i; i = edges[i].__next__)
if(!(edges[i].__forward == fa))
getDeep(edge[i].__forward, u);
}
int32_t __lca__(int32_t u, int32_t v){
if(nodes[u].__depth__ < nodes[v].__depth__) return __lca__;
//ensure the depth[u] is deeper
for(auto h { ( int )std::ceil(std::log2(nodes[u].__depth__ - nodes[v].__depth)) + 1}; h >= 0; --h)
//u should be to the same depth as v
if(nodes[u].__depth <= nodes[v].__depth__)
u = nodes[u].__ancestor__[h];
if(u == v)return u;
//early return
for(auto i {( int )std::ceil(std::log2(nodes[u].__depth__) + 1}; i>=0; --i)
if(!(nodes[u].__ancestor__[i] == nodes[v].__ancestor__[v])){
u = nodes[u].__ancestor__[i];
v = nodes[v].__ancestor__[i];
}
//u and v climb together with the same depth-step
// and should be meet under the their lca in the tree
return nodes[u].__ancestor__[0];
}
方法六
constexpr std::size_t __MAX_NODES_{ 50001U };
constexpr std::size_t __MAX_EDGES_{ 50000U };
constexpr std::size_t __MAX_DEPTH_{ 1 << 4 | 1 };
typedef struct {
int32_t __forward__; //forward adjacent node
int32_t __next__; //next edge
} edge;
typedef struct {
uint32_t __enter__;
uint32_t __leave__;
uint32_t __depth__;
uint32_t __distance__;
int32_t __ancestor__[__MAX_NODES_];
} node;
int32_t head[__MAX_NODES_];
edge edges[__MAX_EDGES_];
node nodes[__MAX_NODES_];
uint32_t tot {};
uint32_t time_stamp {};
void insert(uint32_t u, uint32_t v){
//__COMMENT__: insert a edge from u to v
edges[tot] = edge{ __forward__ : v, __next__ : head[u] };
head[u] = tot ++;
}
inline void __init__(void){
//__COMMENT__: init the head of all edges
std::memset(head, -1, sizeof head);
}
void dfs(int32_t u, int32_t fa){
//__COMMENT__: to mark time stamp and record depth& levelled-ancestor
nodes[u].__enter__ = ++time_stamp;
nodes[u].__ancestor__[0] = fa;
if(fa) nodes[u].__depth__ = nodes[fa].__depth__ + 1;
for(auto i {1U}; (1U << i) < nodes[u].__depth__; ++i)
nodes[u].__ancestor__[i] = nodes[nodes[u].__ancestor__[i-1]].__ancestor__[i-1];
for(auto i {head[u]}; ~i; i = edges[i].__next__)
if(!(edges[i].__forward__ == fa)){
nodes[edges[i].__forward__].__distance__ = nodes[u].__distance__ + 1;
dfs(edges[i].__forward__, u);
}
nodes[u].__leave__ = ++time_stamp;
}
inline bool ancestor_validate(int32_t u, int32_t v){
//__COMMENT__: function to validate node u is whether or not node v's ancestor
return nodes[u].__enter__ <= nodes[v].__enter__
&& nodes[u].__leave__ >= nodes[v].__leave__;
}
int32_t lca(int32_t u, int32_t v){
//__COMMENT__: calculate lca between node u and node v
if(nodes[u].__depth__ < nodes[v].__depth__) return lca(v, u);
if(ancestor_validate(u, v)) return u;
for(int h { ( int )std::ceil(std::log2(nodes[u].__depth__)) + 1}; h >= 0; --h)
if(!ancestor_validate(nodes[u].__ancestor__[h], v))
u = nodes[u].__ancestor__[h];
return nodes[u].__ancestor__[0];
}
inline uint32_t dist(int32_t u, int32_t v, int32_t lca){
//__COMMENT__: calculate distance of node u and node v
return nodes[u].__distance__ + nodes[v].__distance__ - (nodes[lca].__distance__ << 1);
}