すべての境界時間のバランスのとれた二分木を使用できるように思えます。
たとえば、{(1,4), (8,10), (12,15)} を 1、4、8、10、12、および 15 を含むツリーとして表します。
各ノードは、間隔の開始か終了かを示す必要があります。そう:
8 (start)
/ \
1 (start) 12 (start)
\ / \
4 (end) 10 (end) 15 (end)
(ここでは、すべての「終了」ノードが偶然に一番下になりました。)
次に、すべての操作を O(log n) 時間で実行できると思います。間隔を追加するには:
開始時間を見つけます。開始時刻としてすでにツリーにある場合は、そのままにしておくことができます。すでに終了時刻としてツリーにある場合は、削除する必要があります。ツリーに含まれておらず、既存の間隔に該当しない場合は、追加する必要があります。それ以外の場合は、追加したくありません。
同じ方法を使用して停止時間を見つけ、追加する必要があるか、削除する必要があるか、またはどちらも必要ないかを確認します。
ここで、上記の開始ノードと停止ノードを追加または削除し、同時に間にある既存のノードをすべて削除します。これを行うには、ツリー内のこれら 2 つの場所またはそのすぐ上にあるツリー ノードを再構築するだけです。ツリーの高さが O(log n) の場合、バランスのとれたツリーを使用して保証できますが、これには O(log n) の時間がかかります。
(免責事項: C++ で明示的なメモリ管理を行っている場合、これを行うと O(log n) 個を超えるメモリを解放することになる可能性がありますが、実際には、ノードを解放するのにかかる時間は誰にでも請求する必要があります追加したと思います。)
間隔の削除は、ほとんど同じです。
ポイントまたはインターバルのチェックは簡単です。
ノードごとにさらに2つの情報をキャッシュする場合、特定の時間後に少なくとも特定のサイズの最初のギャップを見つけることもO(log n)で実行できます。
特定の時間の後に現れる特定のサイズの最初のギャップを見つけるには、まずツリーでその時間を見つけます。次に、十分な大きさのギャップが含まれていると主張するノードに到達するまで歩きます。右から上がってきた場合は、このギャップが左にあることがわかっているので、それを無視して歩き続けます。そうでなければ、あなたは左から来ました。ノードが開始ノードである場合は、左側のギャップが十分に大きいかどうかを確認します。もしそうなら、あなたは終わりです。それ以外の場合、十分な大きさのギャップは右側のどこかになければなりません。右に歩き、隙間が見つかるまで下ります。繰り返しますが、木の高さは O(log n) であるため、3 回 (下、上、場合によっては再び下) 歩くことは O(log n) です。