===== ISTEM =====
Solve the following programming task.

TASK: Median Finder on a Data Stream

Write a 'MedianFinder' class that accepts numbers from a data stream and computes the running median with O(log n) insertion and O(1) lookup. It must have 'add_num(num)' and 'find_median()' methods.

STARTER CODE (python):
class MedianFinder:
    def __init__(self):
        pass
    def add_num(self, num: int) -> None:
        pass
    def find_median(self) -> float:
        pass


RULES:
- Keep the function name and signature EXACTLY as given.
- Return working code only. No explanations.
- Put the code in a single ``` block.
- Try to solve it first. If you genuinely cannot, write only this single
  line instead of producing faulty code: CANNOT_SOLVE

===== HAM YANIT =====
```python
import heapq

class MedianFinder:
    def __init__(self):
        # max-heap (as negatives) for the lower half
        self.low = []   # largest element at top (as negative)
        # min-heap for the upper half
        self.high = []  # smallest element at top

    def add_num(self, num: int) -> None:
        # Add to max-heap (low) first
        heapq.heappush(self.low, -num)

        # Ensure every element in low is <= every element in high
        if self.low and self.high and (-self.low[0] > self.high[0]):
            val = -heapq.heappop(self.low)
            heapq.heappush(self.high, val)

        # Rebalance sizes: low can have at most one more element than high
        if len(self.low) > len(self.high) + 1:
            heapq.heappush(self.high, -heapq.heappop(self.low))
        elif len(self.high) > len(self.low):
            heapq.heappush(self.low, -heapq.heappop(self.high))

    def find_median(self) -> float:
        if not self.low and not self.high:
            raise ValueError("No elements added")
        if len(self.low) > len(self.high):
            return float(-self.low[0])
        else:
            return (-self.low[0] + self.high[0]) / 2.0
```