Try this one - i think you can get what you want from it. I used a temp table, which you could avoid in one of several ways if you want to, but I think it makes it easier to visualize. I can think of some optimizations as well, but this will work fine for a dataset that isn't too massive. There may also be some boundary conditions I'm not thinking of. Okay, can I qualify my answer any more. . .
--1.Get into temp table
select e.event_id, l.user_id,l.timestamp into #temp from locations l
left join events e on l.timestamp between e.begin_time and e.end_time
and l.latitude between e.min_latitude and e.max_latitude
and l.longitude between e.min_longitude and e.max_longitude
--2.Get when entered and left event
Select t1.*,
CASE WHEN t1.event_id is not null and isnull(t2.event_id,0)<>t1.event_id
THEN 'Yes' ELSE 'No' END As EnteredEvent,
CASE WHEN isnull(t1.event_id,0)<>isnull(t2.event_id,-1) and t2.event_id is not null
THEN 'Yes' ELSE 'No' END As LeftEvent
from
(SELECT t1.*, (
SELECT max(timestamp) as t22
FROM #temp t2
WHERE t1.user_id=t2.user_id and t2.timestamp < t1.timestamp
) as priortimestamp
FROM #temp t1) as t1
LEFT JOIN #temp t2 ON t1.user_id=t2.user_id and t1.priortimestamp=t2.timestamp
ORDER BY t1.user_id, t1.timestamp,t1.event_id
Hope this helps