An alternative (but essentially equivalent to @SamWestrick's) way of thinking about it is to run Dijkstra on the original graph but keeping track of two parameters for each vertex: the shortest path with an even number of red edges found so far, and the shortest with an odd number.
Here's a more precise description of the algorithm. For each vertex $v$, store values $d_{\mathrm{even}}(v),d_{\mathrm{odd}}(v)$. Initialise these by setting $d_{\mathrm{even}}(S)=0$ and all others (including $d_{\mathrm{odd}}(S)$) to $\infty$. For each vertex have two flags $f_{\mathrm{even}},f_{\mathrm{odd}}$ which determine whether the $d$ values are final or not. Initialise all flags to False
.
Now, iteratively do the following. Find a choice of $\mathrm{par}\in\{\mathrm{even},\mathrm{odd}\}$ and $v\in V$ such that $f_{\mathrm{par}}(v)$ is False
and $d_{\mathrm{par}}(v)$ is finite and as small as possible (obviously you can use a priority queue to make this efficient). Write $\mathrm{\overline{par}}$ for the opposite of $\mathrm{par}$.
Now set $f_{\mathrm{par}}(v)$ to True
. For each $vw\in E$,
- if $vw$ is blue, update $d_{\mathrm{par}}(w)$ to $\min\{d_{\mathrm{par}}(w),d_{\mathrm{par}}(v)+\ell(vw)$;
- if $vw$ is red, update $d_{\mathrm{\overline{par}}}(w)$ to $\min\{d_{\mathrm{\overline{par}}}(w),d_{\mathrm{par}}(v)+\ell(vw)$.
Continue to do this until there are no finite distance values for which the corresponding flag is false. (It may be that there are some values which remain infinite, because there is no path from $S$ of the required parity.)
If you need to find the paths, not just the lengths, you similarly need two different variables keeping track of the predecessor of each vertex, which are updated when the corresponding distances are.
This really is exactly the same as @SamWestrick's elegant answer, though: the "odd" variables are just another way of thinking about the variables for the "B copy" of each vertex.