Algorithm for detecting overlaps
I suppose you want to delete as little EmptyEvents as possible.

In that case, you can achieve what you want in O(nlog(n)) time, where n is the number of events.

Proceed as follows:


First, get rid of the EmptyEvents which overlap with a NormalEvent. To do so, put all your starting and ending times in a vector and sort them in increasing order, breaking ties by putting end-times before start-times. Set a counter = 0 and an empty unordered set S. Now go through your vector of times in order. 


Each time you come across the start-time of an EmptyEvent, if counter &gt; 0, then flag that event for deletion. If counter == 0, put that event (or rather its id) in S. 
Each time you come across the end-time of an EmptyEvent, if counter &gt; 0, then flag that event for deletion. Delete the corresponding event from S (if it is still in there). 
Each time you come across the start-time of a NormalEvent, increase the counter by 1.
Each time you come across the end-time of a NormalEvent, decrease the counter by 1, flag all EmptyEvents in S for deletion and clear S.


(then delete all the flagged events)
Then, choose the largest subset of EmptyEvents, no two intersecting. To do so, sort all EmptyEvents according to end-time. Then just go through these events and greedily select one each time it doesn't intersect with the last selected one.
Then, set all the NormalEvent booleans. Set a counter = 0 and prevStart to track the most recent start-time. Sort all NormalEvents start and end-times. Iterate through them in order.


Each time you come across start-time of NormalEvent e, set e.overlapsStart to counter &gt; 0. Then increase counter by 1. Also set prevStart = e.startTime.
Each time you come across end-time of a NormalEvent e, decrease the counter by 1 and set e.overlapsEnd to e.startTime &lt; prevStart.



I'll let you convince yourself of the validity of each step. But here is a good starting point if you are unable to do so :
Interval scheduling on Wikipedia