セグメント ツリーの複雑さを理解するのに問題があります。1 つのノードのみを変更する必要がある update 関数がある場合、その複雑さは log(n) になることは明らかです。しかし、(a、b)がチェックする必要がある間隔であるクエリ(a、b)の複雑さがlog(n)である理由がわかりません。これを理解するための直感的/正式な証拠を誰かに提供してもらえますか?
3 に答える
間隔 (x,y) をクエリする場合は 4 つのケースがあります。
FIND(R,x,y) //R is the node
% Case 1
if R.first = x and R.last = y
return {R}
% Case 2
if y <= R.middle
return FIND(R.leftChild, x, y)
% Case 3
if x >= R.middle + 1
return FIND(R.rightChild, x, y)
% Case 4
P = FIND(R.leftChild, x, R.middle)
Q = FIND(R.rightChild, R.middle + 1, y)
return P union Q.
直観的に、最初の 3 つのケースでは、ツリーの高さのレベルが 1 減少します。ツリーの高さは log n であるため、最初の 3 つのケースのみが発生した場合、実行時間は O(log n) になります。
最後のケースでは、FIND() は問題を 2 つのサブ問題に分割します。ただし、これは多くても 1 回しか発生しないと断言します。FIND(R.leftChild, x, R.middle) を呼び出した後、間隔 [x, R.middle] について R.leftChild を照会しています。R.middle は R.leftChild.last と同じです。x > R.leftChild.middle の場合、ケース 1 です。x <= R.leftChild の場合、呼び出します
FIND ( R.leftChild.leftChild, x, R.leftChild.middle );
FIND ( R.leftChild.rightChild, R.leftChild.middle + 1, , R.leftChild.last );
ただし、2 番目の FIND() は R.leftChild.rightChild.sum を返すため一定の時間がかかり、問題は 2 つの部分問題に分離されません (厳密に言えば、問題は分離されますが、1 つの部分問題は O(1) 時間かかります)。解決する)。
同じ分析が R の rightChild にも当てはまるため、case4 が最初に発生した後、実行時間 T(h) (h はツリーの残りのレベル) は次のようになると結論付けます。
T(h) <= T(h-1) + c (c is a constant)
T(1) = c
これにより、次の結果が得られます。
T(h) <= c * h = O(h) = O(log n) (since h is the height of the tree)
ということで証明を終わります。
貢献するのはこれが初めてです。問題がある場合は、親切に指摘してください。回答を編集します。