Fenwick Tree/B.I.T樹狀數(shù)組算法

樹狀數(shù)組適用范圍:給定區(qū)間稍浆,求最值,求和摇天,區(qū)間單點修改粹湃。
與RMQ不同的是,RMQ一般只用作區(qū)間求最值泉坐。但在最值方面RMQ更加便捷为鳄。

樹狀數(shù)組

從圖上可以看出要找到c[i]的父節(jié)點只要用i+x(x為i轉(zhuǎn)化為二進制從右起第一個出現(xiàn)1的位置)就可以了
尋找x可以通過lowbit函數(shù),即通過計算機補碼的巧用腕让,x=i&(-i)

int lowbit(int x)
{
    return x&(-x);
}

而每一個父節(jié)點存儲的數(shù)據(jù)都是下面所有子節(jié)點的全部信息孤钦。對子節(jié)點修改就必定會對其所有的父節(jié)點進行更新,父節(jié)點c[i]下標的查找如下:

void update(int i, int x)
{
    while(i<=n)
    {
        c[i]+=x;
        i+=lowbit(i);//更新父節(jié)點
    }
}

對于查找1~i的和纯丸、最大值偏形、最小值可以表示為:

int sum(int i)
{
    int res=0;
    while(i>0)
    {
        res+=c[i];
        i-=lowbit(i);
    }
    return res;
}

典型例題(模版):
HDU - 1166
對一個區(qū)域的數(shù)列進行查找、修改

#include<cstdio>
#include<cstring>
using namespace std;

int c[50005];
int n;

int lowbit(int x)
{
    return x&(-x);
}

void update(int i, int x)
{
    while(i<=n)
    {
        c[i]+=x;
        i+=lowbit(i);//更新父節(jié)點
    }
}

int sum(int i)
{
    int res=0;
    while(i>0)
    {
        res+=c[i];
        i-=lowbit(i);
    }
    return res;
}

int main()
{
    int T, cnt;
    scanf("%d", &T);
    for(cnt=1; cnt<=T; cnt++)
    {
        int i, temp;
        char op[10];
        memset(c,0,sizeof(c));

        scanf("%d", &n);
        for(i=1 ;i<=n; i++)
        {
            scanf("%d", &temp);
            update(i, temp);
        }
        printf("Case %d:\n", cnt);
        while(~scanf("%s", op))
        {
            int l, r, k;
            if(!strcmp(op,"End")) break;
            if(!strcmp(op,"Query"))
            {
                scanf("%d%d", &l, &r);
                printf("%d\n", sum(r)-sum(l-1));
            }
            if(!strcmp(op,"Add"))
            {
                scanf("%d%d", &k, &temp);
                update(k, temp);
            }
            if(!strcmp(op,"Sub"))
            {
                scanf("%d%d", &k, &temp);
                update(k, -temp);
            }
        }
    }
    return 0;
}

例題:POJ - 3928
題目大意:在數(shù)列X中找到a觉鼻、b俊扭、c
滿足a<b<c和X[a]<X[b]<X[c]
思路:求取前綴和和后綴和的問題,update(X[i], 1);再getsum()即可

#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long int
const int maxn = 1e5+7;
const int max_num = 1e5;

int a[maxn];
ll c[maxn];

int pos_west[maxn], pos_east[maxn], neg_west[maxn], neg_east[maxn];

int lowbit(int x)
{
    return x&(-x);
}

void update(int i, int p)
{
    while(i<=max_num)
    {
        c[i]+=p;
        i+=lowbit(i);
    }
}

ll getsum(int i)
{
    int res=0;
    while(i>0)
    {
        res+=c[i];
        i-=lowbit(i);
    }
    return res;
}

void init()
{
    memset(a,0,sizeof(a));
    memset(c,0,sizeof(c));
    memset(pos_west,0,sizeof(pos_west));
    memset(pos_east,0,sizeof(pos_east));
    memset(neg_west,0,sizeof(neg_west));
    memset(neg_east,0,sizeof(neg_east));
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        int i, n;
        ll sum=0;
        scanf("%d", &n);
        init();

        for(i=1; i<=n; i++)
        {
            scanf("%d", &a[i]);
            update(a[i],1);
            pos_west[i]=getsum(a[i]-1);
            pos_east[i]=getsum(max_num)-getsum(a[i]);
        }

        memset(c,0,sizeof(c));
        for(i=n; i>0; i--)
        {
            update(a[i],1);
            neg_west[i]=getsum(a[i]-1);
            neg_east[i]=getsum(max_num)-getsum(a[i]);
        }

        for(i=1; i<=n; i++)
        {
            sum+=pos_west[i]*neg_east[i]+neg_west[i]*pos_east[i];
        }
        printf("%I64d\n", sum);
    }
    return 0;
}

注:此方法還可以用來求取逆序數(shù)W钩隆H蟆!

例題:HDU - 1556
給定區(qū)間仇矾,每次在這個區(qū)間加1庸蔼,求每個點一共加了多少次1
思路:前綴和思想,如圖

前綴和
#include<cstdio>
#include<cstring>
using namespace std;

int c[100005];
int n;

int lowbit(int x)
{
    return x&(-x);
}

void update(int i, int p)
{
    while(i<=n)
    {
        c[i]+=p;
        i+=lowbit(i);
    }
}

int getsum(int i)
{
    int res=0;
    while(i>0)
    {
        res+=c[i];
        i-=lowbit(i);
    }
    return res;
}

int main()
{
    while(~scanf("%d", &n)&&n)
    {
        int a, b;
        memset(c,0,sizeof(c));
        for(int i=1; i<=n; i++)
        {
            scanf("%d%d", &a, &b);
            update(a, 1);
            update(b+1, -1);
        }
        for(int i=1; i<=n; i++)
        {
            if(i!=1) printf(" ");
            printf("%d", getsum(i));
        }
        printf("\n");
    }
    return 0;
}
最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贮匕,一起剝皮案震驚了整個濱河市姐仅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,294評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件挨决,死亡現(xiàn)場離奇詭異,居然都是意外死亡壤追,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,493評論 3 385
  • 文/潘曉璐 我一進店門供屉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來行冰,“玉大人溺蕉,你說我怎么就攤上這事〉孔觯” “怎么了疯特?”我有些...
    開封第一講書人閱讀 157,790評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長肛走。 經(jīng)常有香客問我漓雅,道長,這世上最難降的妖魔是什么朽色? 我笑而不...
    開封第一講書人閱讀 56,595評論 1 284
  • 正文 為了忘掉前任邻吞,我火速辦了婚禮,結(jié)果婚禮上葫男,老公的妹妹穿的比我還像新娘抱冷。我一直安慰自己,他們只是感情好梢褐,可當我...
    茶點故事閱讀 65,718評論 6 386
  • 文/花漫 我一把揭開白布旺遮。 她就那樣靜靜地躺著,像睡著了一般盈咳。 火紅的嫁衣襯著肌膚如雪耿眉。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,906評論 1 290
  • 那天鱼响,我揣著相機與錄音鸣剪,去河邊找鬼。 笑死丈积,一個胖子當著我的面吹牛筐骇,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播桶癣,決...
    沈念sama閱讀 39,053評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼娘锁!你這毒婦竟也來了牙寞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,797評論 0 268
  • 序言:老撾萬榮一對情侶失蹤莫秆,失蹤者是張志新(化名)和其女友劉穎间雀,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體镊屎,經(jīng)...
    沈念sama閱讀 44,250評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡惹挟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,570評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了缝驳。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片连锯。...
    茶點故事閱讀 38,711評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡归苍,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出运怖,到底是詐尸還是另有隱情拼弃,我是刑警寧澤,帶...
    沈念sama閱讀 34,388評論 4 332
  • 正文 年R本政府宣布摇展,位于F島的核電站吻氧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏咏连。R本人自食惡果不足惜盯孙,卻給世界環(huán)境...
    茶點故事閱讀 40,018評論 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望祟滴。 院中可真熱鬧振惰,春花似錦、人聲如沸踱启。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,796評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽埠偿。三九已至透罢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間冠蒋,已是汗流浹背羽圃。 一陣腳步聲響...
    開封第一講書人閱讀 32,023評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留抖剿,地道東北人朽寞。 一個月前我還...
    沈念sama閱讀 46,461評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像斩郎,于是被迫代替她去往敵國和親脑融。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,595評論 2 350

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理缩宜,服務發(fā)現(xiàn)肘迎,斷路器,智...
    卡卡羅2017閱讀 134,637評論 18 139
  • 一锻煌、 C/C++程序基礎 面試例題1——分析代碼寫輸出(一般賦值語句的概念和方法)妓布。 面試例題2—...
    LuckTime閱讀 1,970評論 2 42
  • 歸去來兮。 1.1 說明 本篇為《挑戰(zhàn)程序設計競賽(第2版)》[http://www.ituring.com.cn...
    尤汐Yogy閱讀 14,301評論 0 160
  • 漢飛閱讀 183評論 4 0
  • 標題 標題前面加上#號宋梧, 即代表是標題匣沼,1-6級標題,分別對應1-6個#號 列表 無序列表 在列表前面加上-捂龄,即可...
    cpf閱讀 335評論 0 1