因為樹狀陣列不需要構造這一過程,所以先講線段樹的構造
就是用到遞迴:先設left=1,right=n,然後每一次遞迴,left、mid和mid+1、right。**如下:
void build(int left,int right,int index)
單點修改就是每到乙個節點,看這個節點代表著的區間包括不包括這個點,包括就加上。
void my_plus(int index,int dis,int k)
這裡有乙個很關鍵的東西,叫做lowbit,lowbit是將乙個二進位制數的所有高位一都去掉,只留下最低位的1,比如lowbit(5)=lowbit(0101(二進位制))=0001(二進位制)
而如果改變x的值,就要加上自己的lowbit,一直加到n,這些節點都要加,比如一共有8個數第3個數要加上k,那麼c[0011]+=k;
c[0011+0001] (c[0100])+=k;
c[0100+0100] (c[1000])+=k;
這樣就能維護樹狀陣列
void add(int x,int k)
}
區間查詢就是,每查到乙個區間,有三種選擇:
1、如果這個區間被完全包括在目標區間內,那麼加上這個區間的和,然後return;
2、如果這個區間的right>目標區間的left,那麼查詢這個區間;
3、如果這個區間的left《目標區間的right,也查詢這個區間;
void search(int index,int l,int r)
if(tree[index*2].right>=l)
search(index*2,l,r);
if(tree[index*2+1].left<=r)
search(index*2+1,l,r);
}
就是字首和,比如查詢x到y區間的和,那麼就將從1到y的和-從1到x的和。
從1到y的和求法是,將y轉為2進製,然後一直減去lowbit(y),一直到0
比如求1到7的和
ans+=c[0111];
ans+=c[0111-0001(0110)];
ans+=c[0110-0010(0100)];
ans+=c[0100-0100(c[0]無意義,結束)]
int sum(int x)
return ans;
}
和線段樹區間查詢類似,分為三種
1、如果當前區間完全屬於要加的區間,那麼這個區間,也就是節點加上,然後return;
2、如果這個區間的right>目標區間的left,那麼查詢這個區間;
3、如果這個區間的left《目標區間的right,也查詢這個區間;
void pls(int index,int l,int r,int k)
if(tree[index*2].right>=l)
pls(index*2,l,r,k);
if(tree[index*2+1].left<=r)
pls(index*2+1,l,r,k);
}
這就會變的很好玩。如果將x到y區間加上乙個k,那就是從x到n都加上乙個k,再從y+1到n加上乙個-k
加的移動還是i+=lowbit(i);
void add(int x,int k)
}
就是從根節點,一直搜尋到目標節點,然後一路上都加上就好了。
void search(int index,int dis)
從x點,一直x-=lowbit(x),沿途都加上就好啦
int search(int x)
return ans;
}
樹狀陣列與線段樹
推一下關於樹狀陣列的講解部落格 和線段樹的講解 package test2 public class 線段樹 int len a.length segtree t buildtree 0,len 1,a int sum0 2 query t,0,2 int sum1 3 query t,1,3 查詢...
樹狀陣列與線段樹(三)
找規律題 1.螺旋折線 如下圖所示的螺旋折線經過平面上所有整點恰好一次。對於整點 x,y 我們定義它到原點的距離 dis x,y 是從原點到 x,y 的螺旋折線段的長度。例如 dis 0,1 3,dis 2,1 9 給出整點座標 x,y 你能計算出 dis x,y 嗎?輸入格式 包含兩個整數 x,y...
樹狀陣列與線段樹(二)
樹狀陣列 1.小朋友排隊 n n 個小朋友站成一排。現在要把他們按身高從低到高的順序排列,但是每次只能交換位置相鄰的兩個小朋友。每個小朋友都有乙個不高興的程度。開始的時候,所有小朋友的不高興程度都是 0 0 如果某個小朋友第一次被要求交換,則他的不高興程度增加 1 1 如果第二次要求他交換,則他的不...