A tree is a connected acyclic undirected graph. A forest is a disjoint union of trees.

Equivalent definitions

For a graph on vertices, any two of the following imply the third — and all five statements are equivalent:

  1. is connected and acyclic.
  2. is connected and has exactly edges.
  3. is acyclic and has exactly edges.
  4. Between any two vertices there is exactly one simple path.
  5. is connected, and removing any edge disconnects it (every edge is a bridge).

Basic facts

Fact
Edges
Degree sum
Leavesat least 2 (for )
Adding any edgecreates exactly one cycle
Removing any edgecreates exactly two components
Every tree is bipartite2-colour by depth parity
Labelled trees on vertices (Cayley, via Prüfer codes)
Forest with components edges

Rooting a tree

Most tree algorithms want a root. Pick any vertex (or a center when canonicity matters) and DFS.

vector<int> par, depth, sz;
vector<vector<int>> adj;
 
void dfs(int u, int p) {
    par[u] = p;
    sz[u] = 1;
    for (int v : adj[u]) {
        if (v == p) continue;
        depth[v] = depth[u] + 1;
        dfs(v, u);
        sz[u] += sz[v];
    }
}

par, depth and sz are the three arrays nearly every tree algorithm starts from.

Recursion depth

A path-shaped tree with will overflow the default stack on some judges. Either write the DFS iteratively or use an explicit stack:

vector<int> order; order.reserve(n);
stack<pair<int,int>> st; st.push({root, -1});
while (!st.empty()) { auto [u,p] = st.top(); st.pop(); par[u]=p; order.push_back(u);
    for (int v : adj[u]) if (v != p) { depth[v]=depth[u]+1; st.push({v,u}); } }
for (int i = order.size()-1; i >= 0; i--) { int u = order[i]; sz[u]=1;
    for (int v : adj[u]) if (v != par[u]) sz[u] += sz[v]; }

Processing order in reverse is a clean way to do “on the way back up” work without recursion.

Traversal orders

OrderWhen each node is emittedUse
Preorderon entrycopying, prefix expressions, Euler tour
Postorderon exitsubtree aggregation, deletion, tree DP
Inorderbetween children (binary trees)sorted order in a BST
Level order (BFS)by depthshortest paths, level statistics

Standard quantities and how to get them

QuantityMethodTime
Subtree sizesone DFS, accumulate on exit
Diametertwo BFS, or one DFS DP
Centerleaf peeling, or midpoint of the diameter
Centroidthe vertex whose largest subtree is
LCAbinary lifting or Euler + RMQ /
Distance
Sum of all pairwise distancesedge contribution:
Path max/minbinary lifting or HLD

The edge-contribution trick

For any edge splitting the tree into parts of size and , exactly vertex pairs have their path crossing . So

computable in one DFS. This “count the contribution of each edge instead of each path” move solves a whole class of problems.

Centroid

A centroid is a vertex whose removal leaves every component of size . Every tree has one or two, found in one DFS:

int centroid(int u, int p, int n) {
    for (int v : adj[u])
        if (v != p && sz[v] > n / 2) return centroid(v, u, n);
    return u;
}

It is the foundation of centroid decomposition, which is how path-counting problems on trees get an solution.

See also: Tree Diameter · Tree DP · Euler Tour