If you're sticking in the 2d world, a simple grid partition works really well. Divide you're game world into a 2d grid with buckets at each grid box for holding items which are at least partially in that grid box. The size of the buckets is highly application specific, experiment with a combination of small, medium, and large bucket sizes to determine what will work best for you (or create a heuristic for having your game generate bucket sizes for you). Note that it's easiest if all grid boxes are the same size and evenly spaced.
Then place all your world items into the grid (items which overlap multiple buckets are placed in all of those buckets they lie at least partially in). Once you've got the buckets filled, simply use spacial indexing to translate which buckets a particular item of interest (for example, a player) is in, then search those buckets for items and check collision detection between those items and your original item of interest. Once you've found a collision (or possibly multiple collisions, you might be able to handle each collision independently), you can handle specific states here.
For example, if you're character is beneath a platform and you want him to jump up through the platform and land on it, you can detect that you're character has collided with the platform, but he still has an upward velocity so the collision is ignored. However, on the way down his velocity will be directed downwards, and the collision can be registered as landing on the platform. No vertical velocity component (i.e. standing/running on the platform) can probably be handled as if he was landing on the platform.
Alternatively, you could try using a hierarchical system (KD-tree, quad tree, etc.). These systems generalize to higher dimensions really well, though for most 2D collision detection I think they're overkill.