樹狀數組學習筆記

[toc]ios

 

#推薦學習樹狀數組的博客:數組

1.[樹狀數組簡單易懂的詳解](https://blog.csdn.net/flushhip/article/details/79165701)學習

2.[能夠代替線段樹的樹狀數組?——樹狀數組進階(1)](https://www.luogu.org/blog/Chanis/super-BIT)spa

 

#概念.net

樹狀數組顧名思義就是長得像樹的數組(nm這還用你說code

先放張圖看一下下:blog

這是一顆普通的二叉樹ip

巴啦啦能量沙羅沙羅二叉樹全身變:

C[i]表明 子樹的葉子結點的權值之和:ci

C[1]=A[1];
C[2]=A[1]+A[2];
C[3]=A[3];
C[4]=A[1]+A[2]+A[3]+A[4];
C[5]=A[5];
C[6]=A[5]+A[6];
C[7]=A[7];
C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8];

而後在把他們二進制表示一下:將每個二進制,去掉全部高位1,只留下最低位的1,而後從那個數一直加到1get

1=(001)      C[1]=A[1]
2=(010)      C[2]=A[1]+A[2]
3=(011)      C[3]=A[3]
4=(100)      C[4]=A[1]+A[2]+A[3]+A[4]
5=(101)      C[5]=A[5]
6=(110)      C[6]=A[5]+A[6];
7=(111)      C[7]=A[7]
8=(1000)    C[8]=A[1]+A[2]+A[3]+A[4]+A[5]+A[6]+A[7]+A[8]

C[i]=A[i-2^k+1]+A[i-2^k+2]......+A[i] (k爲i的二進制中從最低位到高位連續零的長度)

模板:

lowbit:

#define lowbit(i) i&-i

lowbit(x) 其實就是取出x的最低位1  也就是 lowbit(x)=2^k

區間查詢:

就是前綴和,好比查詢x到y區間的和,那麼就將從1到y的和-從1到x的和。

從1到y的和求法是,將y轉爲2進制,而後一直減去lowbit(y),一直到0

l find(int x) {
    ll kkk=0;
    for(int i=x; i; i-=lowbit(i)) {
        kkk+=t[i];
    }
    return kkk;
}

單點修改:

而若是改變x的值,就要加上本身的lowbit,一直加到n,這些節點都要加,好比一共有8個數第3個數要加上k,那麼c[0011]+=k;

c[0011+0001] (c[0100])+=k;

c[0100+0100] (c[1000])+=k;

這樣就能維護樹狀數組

void insert(int x,int y) {
    for(int i=x; i<=n; i+=lowbit(i)) {
        t[i]+=y;
    }
}

區間修改

這就會變的很好玩。若是將x到y區間加上一個k,那就是從x到n都加上一個k,再從y+1到n加上一個-k

加的移動仍是i+=lowbit(i);

 void add(int x,int k)
    {
        while(x<=n)
        {
            tree[x]+=k;
            x+=lowbit(x);
        }
    }

 

例題:

P3374 【模板】樹狀數組 1

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
#define ll long long int
#define lowbit(i) i&-i
#define MAXN 500050
using namespace std;
const int maxn=999999999;
const int minn=-999999999;
inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
ll t[MAXN],a[MAXN],b[MAXN],ans,n,m;
ll find(int x) {
    ll kkk=0;
    for(int i=x; i; i-=lowbit(i)) {
        kkk+=t[i];
    }
    return kkk;
}
void insert(int x,int y) {
    for(int i=x; i<=n; i+=lowbit(i)) {
        t[i]+=y;;
    }
}
int main() {
    n=read(),m=read();
    for(int i=1; i<=n; ++i) cin>>a[i],insert(i,a[i]);
    while(m--) {
        int p,xx,yy;
        cin>>p>>xx>>yy;
        if(p==1)    insert(xx,yy);
        else if(p==2) cout<<find(yy)-find(xx-1)<<'\n';
    }
    return 0;
}

P3368 【模板】樹狀數組 2

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<vector>
#include<map>
#include<string>
#include<cstring>
#define ll long long int
#define MAXN 500001
#define lowbit(i) i&-i
using namespace std;
const int maxn=999999999;
const int minn=-999999999;
inline int read() {
    char c = getchar();
    int x = 0, f = 1;
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x * f;
}
int t[MAXN],a[MAXN],n,m,ans,last,d[MAXN];
int find(int x) { //單點查詢
    int aans=0;
    /*while(x) {
        aans+=t[x];
        x-=lowbit(x);
    }*/
    for(int i=x; i; i-=lowbit(i)) {
        aans+=t[i];
    }
    return aans;

}
void insert(int x,int y) {
    for(int i=x; i<=n; i+=lowbit(i)) {
        t[i]+=y;

    }
}
int main() {
    n=read();
    m=read();
    for(int i=1; i<=n; ++i) {
        cin>>a[i];
     /*這裏很重要*/
  
  /*

    這裏運用了差分思想,假設本來的數據存在a數組中,
    那麼c數組儲存的就是c[i]=a[i]-a[i-1],若是c[1]=a[1],那麼很明顯
    a[i]=c[i]+c[i-1]+c[i-2]+...+c[2]+c[1].
    這樣咱們每次單點查詢的時候只要加上c數組的前綴就能夠了。
    */

       d[i] = a[i] - a[i-1];
        insert(i, d[i]);
    }
    while(m--) {
        int f,xx,yy,zz;
        cin>>f;
        if(f==1) {
            cin>>xx>>yy>>zz;
            insert(xx,zz);
            insert(yy+1,-zz);//把多的部分刪掉
        } else if(f==2) {
            cin>>xx;
            cout<<find(xx)<<'\n';
        }
    }
    return 0;
}

 

 

 出處:

https://blog.csdn.net/Small_Orange_glory/article/details/81290634)

相關文章
相關標籤/搜索