You track two separate distance arrays: dist[u][0] for the cheapest cost to reach city u without using the discount, and dist[u][1] for the cheapest cost to reach city u after using the discount. Each state in the heap is (cost, city, used), where used is or . When you pop a state, you decide: if used == 0, you can either take the edge normally (push (cost + price, v, 0)) or use the discount (push (cost + price // 2, v, 1)).
If used == 1, you've already spent the discount. You can only take edges at full price, pushing (cost + price, v, 1).