序文
フェンウィックツリーは全体が理解していないので、私はちょうど口胡フェンウィックの木ではなく、特に深い印象の原則結論に対して、インターネットに多くの人々を使用する方法を知っているので、学ぶために始めたとき。その後、再びそれを再学習し、ほとんどフェンウィックツリーの原理を理解することを望んで、フェンウィックツリー上の議論の下で見て知っているが、理解するのは本当に少し難しい、といくつかの神話やイデオロギーがあり、また、いくつかの場所があるかもしれません厳密ではない十分に、私たちは読書の後に願っていますあなたを刺激することができます
導入
我々は2つの操作を実行するために、1次元配列を持っていると仮定します。
1.変更の要素
2.指定した間隔を求め、
この問題については、我々は2つの単純な解決策を持っています
- I変更要素が直接要求間隔と区間に応じて蓄積する($ O(N)$)上で($ O(1)$)インデックスにアクセス$$
- まず、接頭辞及び前処理は、$和[R] -sum [L-1] $間隔とギブ($ O(1)$)が、修飾された要素$ I $は、$ I $接頭辞の前に必須であるとされていますアップデート($ O(n)と$)
両方の方法は、利点と欠点を見ることができる持っているクラスの妥協案はまた、いくつかの間隔の計算結果の時間節約の合計が格納されるが、それによって、更新の数を減らす、重複範囲の数を最小限にすること。
原則
どのように効率的な統計情報のアレイ内のそれを修正するには?私たちは、ツリー構造を使用して考えることができます
あなただけのクエリプレフィックスに必要とし、クエリ木の線分が右息子の値を使用する必要がない場合、これを取り除く(あなたがしなければ、その後、彼の息子の値が使用されている左は、その値は、父ノードとして良いようではありません)示すように、すべての権利の息子が、あなたは、ツリー構造の配列を取得します:
そして、ここでは、木の高さとして解釈さlowbit $ $を置くことができます。観察位置は、第一の層は、すべての$ lowbit(I)= 1 $ノードであり、第二の層がすべてで、対応するノードの高さが$ lowbit(I)$ビット位置し、$ I $のために見つけることができます$ lowbit(I)= 2 $ノード......
高度ノード次に、そのサブツリーの大きさを決定するので、ノード$ I $のために、それは情報区間$(I-lowbit(I)維持 、i]は$を
範囲クエリの場合、我々は右の境界を使用して、プレフィックスとプレフィックスマイナス左マージンを取得しています。
任意の正の整数が追加される2の累乗の形で表現することができるので、その要求は、プレフィックスの複数であってもよく、長さは2の累乗、得られた断面図です。例えば$ 19のため= 2 ^ 2 ^ {4} + {1} + {0}及び^ 2 $、最初の16の要素と、さらに2つの要素とし、さらに得られた要素を追加することです。1、我々はそれにバイナリ和の終わりで除去し続けることができるように、統計情報の対応する範囲。
修正のシングルポイントとして、少し(個人的な意見を)理解するために理解することは少し難しいかもしれ
このルートノードから来た木のメンテナンス間隔情報は、パス上の親ノードに移動するので変更されます。キーは、親を見つけることです、現在のノードの下、私$それは親の$のために、実際には既存のI + lowbit $(I)$、なぜですか?
大きなノードは、情報ノードをカバーするよりも、$ I $の高さは、私は。$ $。私は親ノードが情報の$ I $を覆っている最初のノードで、私たちがしなければならない。$ $は、右の最初の$ heigh(J)> heigh(見つけることです I)$ $ lowbitあるノード$ jの$を、 (J)> lowbit(I) $。それではので、$ jの$を取得する方法?私たちは、直接私が直接可能にプラス$ iのlowbit $ $最小数を増やすことを$、この数字は$ lowbitの$であることは明らかである。lowbit $ $ターゲットを$ $をキャンセルします その結果、$ I + lowbit(I) $は、 私たちが親ノードを探している、などあなたが見上げるのルートに到達するまで、何です
実現
おそらくクリアされます思考の多くを実装するために、後フェンウィックツリーの原則を理解します
int lowbit(int x){ return x&(-x); } //区间求和 int sum(int x){ int ret = 0 while(i){ ret += c[x]; x -= lowbit(x); } return ret; } //单点修改 void update(int x, int val){ while(x<=n){ c[x] += val; x += lowbit(x); //向上更新 } }
这里解释下$lowbit(i)$为什么可以用$i\&(-i)$表示,计算机中的负数用对应正数的补码(正数取反加一)来表示
假设这里的$i$我表示成xxxxx100,那么$-i$就是#####011+1 = #####100(这里的#表示对x取反)
那么(xxxxx100)&(#####100) = 00000100,就是$i$的二进制的最低位1对应的值
Reference:
https://www.zhihu.com/question/54404092
https://www.cnblogs.com/acgoto/p/8583952.html