樹狀陣列的分析

2021-09-18 04:39:34 字數 3492 閱讀 3822

參考

c[i]代表 子樹的葉子結點的權值之和// 這裡以求和舉例

如圖可以知道

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];

將c陣列的結點序號轉化為二進位制

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的二進位制中從最低位到高位連續零的長度)例如i=8時,k=3;

換一種巧妙方式標示2^k(k為i的二進位制中從最低位到高位連續零的長度)

比如說t為110時k應該為1這是怎麼做呢??

用t&-t

int lowbit(int t)

//-t 代表t的負數 計算機中負數使用對應的正數的補碼來表示

//例如 :

// t=6(0110) 此時 k=1

//-t=-6=(1001+1)=(1010)

// t&(-t)=(0010)=2=2^1

你可以用幾個例子試一下發現是不是很神奇?

所以公式可以寫成c[i]=a[i-lowbit(i)+1]+a[i-lowbit(i)+2]+…a[i];(替換沒用的2^k)

利用c[i]中介再好好看看上面的圖求a陣列前i項和,,

舉個例子 i=7;

sum[7]=a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7] ; 前i項和

c[4]=a[1]+a[2]+a[3]+a[4]; c[6]=a[5]+a[6]; c[7]=a[7];

可以推出: sum[7]=c[4]+c[6]+c[7];

序號寫為二進位制: sum[(111)]=c[(100)]+c[(110)]+c[(111)];

舉個例子 i=7; …………………… 111

sum[7]=a[1]+a[2]+a[3]+a[4]+a[5]+a[6]+a[7] ; 前i項和

c[4]=a[1]+a[2]+a[3]+a[4]; c[6]=a[5]+a[6]; c[7]=a[7];

可以推出: sum[7]=c[4]+c[6]+c[7];

序號寫為二進位制: sum[(111)]=c[(100)]+c[(110)]+c[(111)];

7(111) sum+=c[7]

lowbit(7)=1 7-lowbit(111)=6(110) sum+=c[6]

lowbit(6)=2 6-lowbit(6)=4(100) sum+=c[4]

lowbit(4)=4 4-lowbit(4)=0(000)

再舉個例子 i=5

sum[5]=a[1]+a[2]+a[3]+a[4]+a[5] ; 前i項和

c[4]=a[1]+a[2]+a[3]+a[4]; c[5]=a[5];

可以推出: sum[5]=c[4]+c[5];

序號寫為二進位制: sum[(101)]=c[(100)]+c[(101)];

int getsum(int x)

單點更新

當我們修改a陣列中的某乙個值時 應當如何更新c陣列呢?

回想一下 區間查詢的過程,再看一下上文中列出的圖

結合**分析

void add(int x,int y)

//可以發現 更新過程是查詢過程的逆過程

//由葉子結點向上更新c陣列

如圖:當更新a[1]時 需要向上更新c[1] ,c[2],c[4],c[8]

c[1], c[2], c[4], c[8]

寫為二進位制 c[(001)],c[(010)],c[(100)],c[(1000)]

1(001) c[1]+=a[1]

lowbit(1)=001 1+lowbit(1)=2(010) c[2]+=a[1]

lowbit(2)=010 2+lowbit(2)=4(100) c[4]+=a[1]

lowbit(4)=100 4+lowbit(4)=8(1000) c[8]+=a[1]

做題:單擊傳送門移步hdu敵兵布陣

#include #include #include #include #include #include #include #include #include #define for(a,b) for(int a=0;a> t ;

for(int j=1;j<=t;j++)

cout < s;

if(s[0] == 'e')

break;

scanf("%d%d",&x,&y);

if(s[0] == 'q')

cout << getsum(y)-getsum(x-1)離散化+樹狀陣列求逆序數

#include #include #include using namespace std;

typedef long long ll;

const int n=5e5+10;

struct nodep[n];

int n,bit[n],a[n];

bool cmp(const node&a, const node& b)

return s;}

void solve()

sort(p+1,p+n+1,cmp);//排序

for(int i=1; i<=n; i++)a[p[i].pos]=i;//離散化,a[i]表示原來排序前第i號位置應該放在a[i]位置上

ll ans=0;

for (int i=1; i<=n; i++) bit[i]=0; //初始化樹狀陣列

for(int i=1; i<=n; i++)

printf("%i64d\n",ans);}

int main()

return 0;

}

對這一題給出的**如有疑問參考解釋

樹狀陣列演算法分析

樹狀陣列演算法分析,最近經常碰到樹狀陣列的問題,就不如寫一寫對這個演算法的理解吧 先偷一張圖 大概理解就是,對於 c陣列 是整個樹狀陣列裡的靈魂,也可是tree 陣列,其實a 陣列 是不存在的 可以這麼理解 借勢,c 8 c 4 c 6 c 7 a 8 而 c 4 c 2 c 3 a 4 c 6 c...

樹狀陣列演算法分析

最近經常碰到樹狀陣列的問題,就不如寫一寫對這個演算法的理解吧 先偷一張圖 大概理解就是,對於 c陣列 是整個樹狀陣列裡的靈魂,也可是tree 陣列,其實a 陣列 是不存在的 可以這麼理解 借勢,c 8 c 4 c 6 c 7 a 8 而 c 4 c 2 c 3 a 4 c 6 c 5 a 6 對於 ...

樹狀陣列2 更高深的樹狀陣列

一 區間修改區間求和 這個東西可就不是把 單點查詢區間修改 和 單點修改區間查詢 合起來那麼簡單了,仔細想想,拿之前的辦法都不咋地好做,那麼怎麼辦呢,我們還是要用到差分陣列,設原陣列為a,差分陣列為b,則b 1 a 1 b i a i a i 1 那麼區間修改我們就解決了,只需要log的時間即可,但...