セグメントツリー内のノードにクエリを実行するときは、すべての祖先とノード自体が適切に更新されていることを確認する必要があります。これは、クエリノードにアクセスしているときに行います。
クエリノードにアクセスしている間は、保留中のすべての更新を処理しながら、ルートからクエリノードへのパスをトラバースします。あなたが訪問する必要があるO(log N)祖先があるので、任意の与えられたクエリノードに対して、あなたはO(ログN)の作業しか行いません。
以下は、遅延伝播を伴うセグメントツリーのコードです。
// interval updates, interval queries (lazy propagation)
const int SN = 256; // must be a power of 2
struct SegmentTree {
// T[x] is the (properly updated) sum of indices represented by node x
// U[x] is pending increment for _each_ node in the subtree rooted at x
int T[2*SN], U[2*SN];
SegmentTree() { clear(T,0), clear(U,0); }
// increment every index in [ia,ib) by incr
// the current node is x which represents the interval [a,b)
void update(int incr, int ia, int ib, int x = 1, int a = 0, int b = SN) { // [a,b)
ia = max(ia,a), ib = min(ib,b); // intersect [ia,ib) with [a,b)
if(ia >= ib) return; // [ia,ib) is empty
if(ia == a && ib == b) { // We push the increment to 'pending increments'
U[x] += incr; // And stop recursing
return;
}
T[x] += incr * (ib - ia); // Update the current node
update(incr,ia,ib,2*x,a,(a+b)/2); // And push the increment to its children
update(incr,ia,ib,2*x+1,(a+b)/2, b);
}
int query(int ia, int ib, int x = 1, int a = 0, int b = SN) {
ia = max(ia,a), ib = min(ib,b); // intersect [ia,ib) with [a,b)
if(ia >= ib) return 0; // [ia,ib) is empty
if(ia == a && ib == b)
return U[x]*(b - a) + T[x];
T[x] += (b - a) * U[x]; // Carry out the pending increments
U[2*x] += U[x], U[2*x+1] += U[x]; // Push to the childrens' 'pending increments'
U[x] = 0;
return query(ia,ib,2*x,a,(a+b)/2) + query(ia,ib,2*x+1,(a+b)/2,b);
}
};
私は、セグメントツリーを実装した場合、私は同じことをしなければなりませんでした。 [0-> 4]ノードを設定し、各子にマークを付け、親ノードをルートまで更新します。 – Justin
あなたのアップデートはO(logN)でしたか?また、セグメントツリーで、範囲が2〜7の場合は、3つのセグメントを更新します。 rt? [2 2]、[3 4] [5 7] – Pranalee
O(2 * logn)更新。そうです、それは最悪の場合のアップデートです。誰かがより良いアプローチを知っているなら、私は不思議に思うだろう。 – Justin