I second what Hodgman said.
I'll also add, that we have a BVH (Bounding Volume Hierarchy) for lights. Their bounding volumes represent area that light affects (e.g. for point light we have a sphere, for spot light it is a cone, and similarly for area lights (as we do support them in our tech)).
Now, first we can quickly tell whether we have to compute with given light (e.g. whether it affects any pixel in given view frustum), second we can quickly tell which lights affect each given object.
The objects we need to test are taken from another BVH, that contains scene objects (we actually split objects in static and dynamic ones - because for static objects you don't need to rebuild the hierarchy, for dynamics you need to either rebuild, or sometimes just refit).
So basically we're working with multiple "scene graphs" in our tech (BVH is actually an implementation that can be used as scene graph). To explain a little bit about BVH (unless you know what it's all about) - check http://en.wikipedia.org/wiki/Bounding_volume_hierarchy
Technically you could also use some spatial hierarchy for this - KD-trees or Octrees for example.