日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

树状数组基础原理与模板

發布時間:2023/12/19 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 树状数组基础原理与模板 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

樹狀數組

2021年7月29

1、算法原理

樹狀數組解決什么問題?

解決區間上點更新與維護的問題。如更改某些點值求區間和,或求某位前有多少比其小的問題。

其實現的原理是什么?

首先看圖:

在這個圖中,將每1<<i個數(0<=i<=n)分為一組 ,此時設置函數lowbit(i),此函數將i的2進制中最后一位1前的數字全部刪去,如lowbit(6)=4。

由圖可看出,對于每個i,其都存在在其本身與i+lowbit(i)的區間數組內。例如:5—>101,101+1=110,此時存在于下標為6的區間內,隨后,110+10=1000,1000+1000=10000,因此,5同時存在于下標為8與下標為16的區間內。

由此,可對數組進行更新操作:

for( ;i <= n; i+=lowbit(i)){tre[i]+=1;//此處不一定為1,根據題目不同更改,先對應下面樣例 }

對于最大值為n的樹狀數組,每次將i加入相應區間。

那么,怎么進行查詢操作?

對于一個數i可知,小于等于其本身的數字一定都存在于比其下標更小的數組里。因此此處依然可以按照二進制位進行查詢,為了避免重復查詢,依次進行i-lowbir(i)的操作進行查詢,如:11—>1011,1011-1=1010,1010-10=1000,1000-1000=0(若下標從1開始可不要),此時查詢的下標為10,8,由圖可知,所有小于等于11的數字,均存在于下標為10和8的數組內。

因此有查詢操作:

for( ; i > 0; i-=lowbit(i)){res+=tre[i]; }

2、模板題:

描述:

第一行輸入一個n,接下來一行輸入n個數,為a1…an,1<=ai<=1e4。

接下來一行輸出n個數,對于每個ai,輸出其之前比它小的數字的數量。

#include<iostream> #include<algorithm> #include<stdio.h>using namespace std;int n,num; int tre[1005],ans[1005];int lowbit(int i){return (i & -i); }void settre(int i){for( ; i < 1005; i += lowbit(i)){tre[i]++;} }int solvetre(int i){int res = 0;for( ; i; i -= lowbit(i)){res+=tre[i];}return res; }int main(){cin>>n;for(int i = 1; i <= n; i++){cin>>num;ans[i]=solvetre(num-1);settre(num);}cout<<ans[1];for(int i = 2; i <= n; i++){cout<<' '<<ans[i];}cout<<'\n';return 0; }

輸入樣例:

9 1 5 2 9 4 1 7 8 3

輸出樣例:

0 1 1 3 2 0 5 6 3

3、實操例題

ACwing 242. 一個簡單的整數問題

分析:

本題應將第i個數的差分存入樹狀數組,以便查詢。

AC代碼:
#include<iostream> #include<algorithm> #include<stdio.h> #include<string> #include<string.h> typedef long long ll;using namespace std;int n, m, num; int a, b; ll tre[100005]; int sic[100005]; string k;ll lowbit(ll i) {return (i & -i); }void settre(int i, int c) {for (; i < n + 1; i += lowbit(i)) {tre[i] += c;} }ll solvetre(int i) {ll res = 0;for (; i; i -= lowbit(i)) {res += tre[i];}return res; }int main() {cin >> n >> m;for (int i = 1; i <= n; i++) {cin >> sic[i];}for (int i = 1; i <= n; i++) {settre(i, sic[i] - sic[i - 1]);}while(m--){cin >> k;if (k == "Q") {cin >> num;cout << solvetre(num) << endl;}else {cin >> a >> b >> num;settre(a, num); settre(b + 1, -num);}}return 0; }

總結

以上是生活随笔為你收集整理的树状数组基础原理与模板的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。