Parity Toggle Layers
You're walking through a dungeon. Some doors are open, others locked. Then you step on a pressure plate --- every door flips. Open ones slam shut. Locked ones swing wide. The maze you memorized is now a different maze. Same nodes, different edges.
This is the toggle pattern. The graph has two faces, and switches flip between them. To track which face you're on, you add one bit to your state.
The Setup: AtCoder abc277_e (Crystal Switches)

\(N\) vertices, \(M\) edges. Each edge has a flag \(a_i \in \{0, 1\}\). If \(a_i = 0\), the edge only works when switches are in state 0. If \(a_i = 1\), it only works in state 1. You start in state 0.
\(K\) vertices have crystal switches. Stepping on one toggles the global state: all edges swap their active/inactive status.
Find the minimum number of moves from vertex 1 to vertex \(N\). Each move traverses one active edge.
The State Space
At any point, you care about two things:
- Where you are --- which vertex.
- Which edges are active --- the parity (0 or 1).
State: (vertex, parity). This gives \(2N\) states total.
Building the 2-Layer Graph
Visualize two copies of the graph stacked vertically:
In layer 0, only edges with \(a = 0\) are active. In layer 1, only edges with \(a = 1\). These are separate subgraphs --- except at switch vertices, where you can jump between layers.
At a switch vertex \(v\): edge from \((v, 0)\) to \((v, 1)\) and back, with cost 0. The switch is free; it just flips the world.
Key insight. The toggle doesn't move you. It changes the world around you. In the layered graph, this is a vertical edge at the same vertex with cost 0.
0-1 BFS on the Layered Graph
Edges within a layer cost 1 (one move). Switch edges between layers cost 0 (no move consumed). This is a textbook 0-1 BFS: use a deque, push cost-0 transitions to the front, cost-1 transitions to the back.
deque<tuple<int,int>> dq;
dist[0][0] = 0;
dq.push_back({0, 0}); // (parity, vertex_0indexed)
while (!dq.empty()) {
auto [p, u] = dq.front(); dq.pop_front();
// Traverse active edges (cost 1)
for (int v : adj[p][u]) {
if (dist[p][v] == -1) {
dist[p][v] = dist[p][u] + 1;
dq.push_back({p, v});
}
}
// Toggle at switch (cost 0)
if (has_switch[u] && dist[1-p][u] == -1) {
dist[1-p][u] = dist[p][u];
dq.push_front({1-p, u});
}
}
Gotcha. A common mistake is using a regular queue and treating switch transitions as cost 1. This overcounts by 1 for every toggle used and gives WA.
Trace: 5-Vertex Example
Vertices: 1--5. Start = 1, Target = 5. Switch at vertex 3.
| Edge | Vertices | Active in |
|---|---|---|
| 1 | 1 -- 2 | parity 0 |
| 2 | 2 -- 3 | parity 0 |
| 3 | 3 -- 4 | parity 1 |
| 4 | 4 -- 5 | parity 1 |
| 5 | 1 -- 5 | parity 1 |
In parity 0, we can only traverse edges 1 and 2. In parity 1, edges 3, 4, and 5.
| Step | Pop (p, u) | dist[p][u] | Action |
|---|---|---|---|
| 1 | (0, 1) | 0 | push (0, 2) dist=1 |
| 2 | (0, 2) | 1 | push (0, 3) dist=2 |
| 3 | (0, 3) | 2 | switch! push_front (1, 3) dist=2 |
| 4 | (1, 3) | 2 | push (1, 4) dist=3 |
| 5 | (1, 4) | 3 | push (1, 5) dist=4 |
| 6 | (1, 5) | 4 | target! |
Answer: 4. Path: 1 -> 2 -> 3 -> [toggle] -> 4 -> 5.
Without the toggle, vertex 5 is unreachable in parity 0. The switch at vertex 3 opens up the parity-1 edges.
Variant: Expensive Toggles (AtCoder abc395_e)
AtCoder abc395_e (Flip Edge) is the same pattern, but flipping costs \(X\) instead of 0. Now 0-1 BFS becomes Dijkstra.
The only structural change: the vertical edge between layers has cost \(X\).
No switches restrict where you can toggle --- you can flip at any vertex, any time. The question becomes: is paying \(X\) to access different edges worth it?
Key insight. When toggles are free, you flip whenever it helps. When toggles cost \(X\), you have a cost-benefit tradeoff. Dijkstra resolves this automatically --- it never needs you to reason about when to flip.
Variant: Alternating Colors (LC 1129)
LC 1129 (Shortest Path with Alternating Colors) is parity without a switch. Edges are colored red or blue. You must alternate colors on consecutive steps.
State: (node, last_color). Two layers again.
// From layer 0 (last = red), can only take blue edges
for (int v : blue_adj[u]) {
if (dist[1][v] == -1) {
dist[1][v] = dist[0][u] + 1;
q.push({1, v});
}
}
// From layer 1 (last = blue), can only take red edges
for (int v : red_adj[u]) {
if (dist[0][v] == -1) {
dist[0][v] = dist[1][u] + 1;
q.push({0, v});
}
}
Every edge forces a layer change. There are no within-layer edges. This is a parity constraint, not a controllable toggle --- but the layered graph construction is identical.
Gotcha. In LC 1129, the first move can use either color. Initialize both
dist[0][0] = 0anddist[1][0] = 0, or add a virtual source connected to node 0 in both layers.
The General Toggle Pattern
All three problems share the same skeleton:
- Identify the binary state that changes the graph's edges.
- Build two layers of the graph, one per state value.
- Connect layers at transition points (switches, forced alternation, paid flips).
- Run BFS or Dijkstra on the \(2N\)-node expanded graph.
The binary state varies by problem:
| Problem | Binary state | What it controls |
|---|---|---|
| Crystal Switches | switch parity | which edge set is active |
| Flip Edge | flip parity | which edge set is active |
| Alternating Colors | last edge color | which edges are available next |
| Day/night cycle | time mod 2 | which edges are open |
When Not To Expand
If the parity is fully determined by BFS depth (e.g., "alternate every step, no choice"), you can track it implicitly via dist % 2. But when different paths reach the same node with different parities, or when toggling is optional, explicit layers are necessary.
The cost of explicit layers is negligible: \(2N\) states, \(2M + K\) edges.
Complexity
- States: \(2N\).
- Edges: \(2M + K\) (original edges in each layer, plus switch transitions).
- 0-1 BFS: \(O(N + M)\).
- Dijkstra (weighted toggles): \(O((N + M) \log N)\).
Doubling the graph is nearly free.
Exercises
-
Layer design. A graph has three types of edges: A, B, C. A switch cycles through which type is active (A -> B -> C -> A). How many layers do you need? What's the state?
-
Reachability. In the crystal switches problem, can you always reach both layers from the start? What conditions would make one layer permanently unreachable?
-
Answer extraction. Your BFS finishes.
dist[0][N] = 7anddist[1][N] = 5. What's the answer? Does it matter which layer you end in?
Problems
| Problem | Link | Difficulty |
|---|---|---|
| AtCoder abc277_e --- Crystal Switches | atcoder.jp/contests/abc277/tasks/abc277_e | Hard |
| AtCoder abc395_e --- Flip Edge | atcoder.jp/contests/abc395/tasks/abc395_e | Hard |
| LC 1129 --- Shortest Path with Alternating Colors | leetcode.com/problems/shortest-path-with-alternating-colors | Medium |