フェンウィックツリーシステムを研究するために、「学ぶことをお勧めしますバイナリ分解」、「倍増」という概念を。
簡単な紹介
フェンウィックツリーは道でありますO (ログN )完全な範囲内[ 1 、N ]添加問い合わせ(和、積)でO (ログN )完全な単一変更データ構造データ(基本動作の二種以上)。
その小さな符号量、小さい定数が、(可能要求値間隔をサポートしていないほとんどのセグメントツリーを使用します)。
原則
実際には、コアアイデアフェンウィックツリーがさ倍増、基本的に、フェンウィックツリーはSTアルゴリズムの拡張版です。
ST表非添加メイン処理部の問題、およびそれに類似フェンウィックツリーは間隔が問題を増加させることができる決定することができます。
テンプレート:
int lowbit(int x){
return x&(-x);
}
int que_sum(int x){
int sum = 0;
for( ; x > 0; x -= lowbit(x))
sum += val[x];
return sum;
}
void update(int x, int k){
for( ; x <= n; x += lowbit(x))
val[x] += k;
}
インターバル動作を使用することができる差動範囲について、[ L 、R ]私たちは、最初のウィンドウを処理します[ 1 、L - 1 ]処理ウィンドウで[ 1 、R ]そして、減算を行う、あなたは答えを得ることができます。
操作の変更、ポイントの各変更について、限り、我々はうまくこの時点のカバレッジ情報セクションを更新してきたように、デジタルXカバレッジの方法を見つけるための情報の次の部分がありますX + = リットルO W B I T (X )、電流は最下位ビットを運ぶことができるように、変更の最小で覆わなければならない点の数は、この停止に追加されているが、Nよりも大きいです。
この最適化は、バイナリ分解の唯一のラインは、そのメンテナンス情報、情報の保守サポートの変更を削減するため、一定の変動が非常に小さい、単純な乗算ツリーの最も基本的な最適化の配列です。
準備機能[ 編集]
最後の位置によって表されるバイナリ値にパラメータを返す関数を定義Lowbit。
例えば、戻り値のLowbit(34)は2である;そしてLowbit(12)戻り4; Lowbit(8)8戻ります。
バイナリに34、0010 0010で、 "最後の1"とは、{\ ^ {0} displaystyle 2 } ビットフォワード番号を、最初のものを参照して、即ち{\ displaystyle 2 ^ {1}} 1位。
プログラムでは、((未I)+1)そして、私は1の最後の値を示し、
実施例34は、依然として、ません結果1101 1101 0010 0010(221)1101 1110(222)を添加した後、およびAS 00100010 11011110 AND、0000 0010(2)を与えることです。
(C ++):見つけるための簡単な方法のLowbit
INT lowbit (INT X )
{
戻り X &(- X )。
}
リファレンス+推奨:
http://blog.csdn.net/yhf_2015/article/details/53844284
http://blog.csdn.net/int64ago/article/details/7429868
http://blog.csdn.net/x_iya/article/details/8943264
ウィキペディアは言います:
フェンウィックツリー[ 編集]
フェンウィックツリーやバイナリインデックスツリー(英語バイナリインデックスツリー最初の新たな累積A周波数のためのデータ構造と1994年にピーター・M.フェンウィックによって提案された)、及びその発明者の名前フェンウィックツリーは、テーブルには、[1]のタイトルで出版され練習とソフトウェアでの経験。その意図は、現在、効率的な接頭辞の計算および列数、および間隔に使用される累積度数(累積度数)計算問題で圧縮されたデータを、解決することです。あってもよい{\ displaystyle O(\ Nログ )} 接頭辞と時間を与えるために{\ DisplayStyle \ SUM _ {私は= 1} ^ {J} A [I] ,. 1 <= J <= N}と同時に、を支持{\ displaystyle O(\ログN )} 修正支持動的単一の時間ポイント値。空間複雑{\ DisplayStyle O(N)}。
準備機能[ 編集]
最後の位置によって表されるバイナリ値にパラメータを返す関数を定義Lowbit。
例えば、戻り値のLowbit(34)は2である;そしてLowbit(12)戻り4; Lowbit(8)8戻ります。
将34转为二进制,为0010 0010,这里的"最后一个1"指的是从{\displaystyle 2^{0}}位往前数,见到的第一个1,也就是{\displaystyle 2^{1}}位上的1.
程序上,((Not I)+1) And I表明了最后一位1的值,
仍然以34为例,Not 0010 0010的结果是 1101 1101(221),加一后为 1101 1110(222), 把 0010 0010与1101 1110作AND,得0000 0010(2).
Lowbit的一个简便求法:(C++)
int lowbit(int x)
{
return x&(-x);
}
新建[编辑]
定义一个数组 BIT,用以维护{\displaystyle A}的前缀和,则:
{\displaystyle BIT_{i}=\sum _{j=i-lowbit(i)+1}^{i}A_{j}}
具体能用以下方式实现:(C++)
void build()
{
for (int i=1;i<=MAX_N;i++)
{
BIT[i]=A[i];
for (int j=i-1; j>i-lowbit(i); j--)
BIT[i]+=A[j];
}
}
//注:这里的求和将汇集到非终端结点(D00形式)
//BIT中仅非终端结点i值是 第0~i元素的和
//终端结点位置的元素和,将在求和函数中求得
修改[编辑]
假设现在要将{\displaystyle A[i]}的值增加delta,
那么,需要将{\displaystyle BIT[i]}覆盖的区间包含{\displaystyle A[i]}的值都加上delta.
这个过程可以写成递归,或者普通的循环.
需要计算的次数与数据规模N的二进制位数有关,即这部分的时间复杂度是O(LogN)
修改函数的C++写法
void edit(int i, int delta)
{
for (int j = i; j <= MAX_N; j += lowbit(j))
BIT[j] += delta;
}
求和[编辑]
假设我们需要计算{\displaystyle \sum _{i=1}^{k}A_{i}}的值.
- 首先,将ans初始化为0,将i初始化为k.
- 将ans的值加上BIT[i]
- 将i的值减去lowbit(i)
- 重复步骤2~3,直到i的值变为0
求和函数的C/C++写法
int sum (int k)
{
int ans = 0;
for (int i = k; i > 0; i -= lowbit(i))
ans += BIT[i];
return ans;
}
复杂度[编辑]
初始化复杂度最优为{\displaystyle O(N)}
单次询问复杂度{\displaystyle O(\log N)},其中N为数组大小
单次修改复杂度{\displaystyle O(\log N)},其中N为数组大小
空间复杂度{\displaystyle O(N)}
アプリケーションの[ 編集]
逆数を探している[5] [ 編集]
リバース数は、それが多数を持っているよりも、その前に一連の数字です。逆の順序番号4312は1 + 0 + 2 + 2 = 5です。
現在の数より照会数以上の数で、最初の数からフェンウィックツリー内の各時間を通過し、現在の要素がフェンウィックツリーを追加された後、カウンタを追加します。