線段樹,樹狀陣列,主席樹

2021-08-21 20:59:22 字數 3108 閱讀 4871

樹狀陣列

主席樹—-包括無修改和可修改。

用乙個滿二叉樹(葉子節點可以為空)來維護乙個連續陣列,整個樹的所有葉子節點從左到右表示整個陣列,每個非葉子節點表示其所有葉子的集合所描述的乙個連續子陣列的某一特性(最小值,最大值等)。

可以在logn的複雜度內實現對任意連續欄位的給定特性的查詢(最小值等),可以在logn的時間內完成對任意連續欄位的修改(都改變相同的量)

struct segtreenodesegtree[10000];
void build(int root, int* array, int s, int e)

int mid = (s+e)>>1;

build(root*2+1,array,s,mid); //左子樹

build(root*2+2,array,mid+1,e); //右子樹

segtree[root].val = min(segtree[root*2+1].val,segtree[root*2+2].val);

}

void pushdown(int root)
void update(int root, int ns,int

ne,int

s,int e,int addval)

pushdown(root);

int nm = (ns+ne)>>1;

update(root*2+1,ns,nm,s,e,addval);

update(root*2+1,nm+1,ne,s,e,addval);

segtree[root].val = min(segtree[root*2+1].val,segtree[root*2+2].val);

}

int query(int root,int ns,int

ne,int

s,int e)

樹狀陣列是一顆樹,它的所有葉子節點從左到右對應乙個連續陣列,用s1,s2,…,sn表示。非葉子節點樹與非葉子節點樹相同,表示為t1,t2,…,tn,其每個非葉子節點ti有ki個子節點,ki的大小與i的二進位制的最後乙個1的大小相同(如 10 對應2, 100 對應 4)。每個葉子節點si的父節點是ti,每個非葉子節點ti的父節點是t(i+ki)。每個非葉子節點中記錄了它的所有葉子節點的屬性(一般是和)。

第一是每個非葉子節點ti的值對應了s(i-ki+1)到 si 這ki個連續資料的屬性(一般是和),因此可以查詢任意連續區間的屬性,且複雜度為logn。第二是可以對單個數si做修改,修改的複雜度是logn。

int

val[1000],sum

[1000];

void lowbit(int i)
void build(int n)
int sum_i(int i)

int query(int s,int e)

void update(int i,int val,int n)
主席樹是由乙個連續陣列的很多顆字首樹所組成的,每乙個字首1到i對應一顆樹ti。每棵樹有相同的結構,可以實現樹之間的加減,對於每棵樹的葉子節點,包含了一些該字首的屬性資訊(由於主席樹主要用來求第k大的數,因此包含的資訊一般是第i個節點的值表示該字首中第i小的數的個數),而非葉子節點的值為其子節點之和。且利用相鄰的兩棵淺醉樹只相差乙個樹,也就只有乙個飛葉子節點值不同,在樹中也就一條路徑不同,於是公用其他部分,只需一條新路徑即可。

由於每棵樹的結構都是一樣的,且非葉子節點表示大小排第i的數的個數,因此需要在開始前確定樹的結構,在此使用的是滿二叉樹,因此也就等價於需要確定葉子節點的個數,葉子節點對於與陣列中樹的大小排名,因此需確定陣列中有多少個不同的數,這一點對於無修改的很簡單,但對於有修改的就需要先知道所有修改後的值。

對於可修改的情況,我們使用乙個陣列陣列來維護修改值,也就是先確定無修改的主席樹,然後新建乙個樹狀陣列,樹狀陣列的每個節點也是乙個同樣結構的二叉樹,但起始時都是空樹(不佔空間),根據樹狀陣列的特徵知每次修改只與logn個節點相關,而對每個節點,也就是最多會改變其二叉樹的兩個葉子節點的值,影響兩條路徑,這是修改或動態新增該路徑即可,只有logn的消耗(時間和空間)。

因此總的時間與空間消耗複雜度都是一樣的,無修改時為nlogn,修改時為nlognlogn

int main

st[1]=val[rank[1]];

val[rank[1]] = 1;

...}

int val[1000]; //原陣列

int s[1000],t[1000],tot,size;

int l[100],r[100]; // 用於查詢時維護樹狀陣列,對應於每個節點的樹的子樹。

struct chairtreenodechairtree[100000];

void buildnode(int &root,int preroot,int l,int r,int x)
void build(int n)
void update(int &root,int

index,int op,int s,int e)

chairtree[root].v+=op;

if(s==e) return;

int mid = s+e>>1;

if(x<=s) update(chairtree[root].l,x,op,s,mid);

else update(chairtree[root].r,x,op,mid+1,e);

}void add(int

index,int x,int op)

int query(int lroot,int rroot,int s,int e,int k)else

}int query(int s,int e,int k)

可修改主席樹 樹狀陣列套主席樹

普通主席樹可以查詢區間k小值,但若直接修改,則複雜度極大,而可修改主席樹通過樹狀陣列的輔助來修改,大大縮小了時間複雜度,缺點是空間複雜度過大.修改的時間複雜度為o logn 2 空間複雜度為o n logn 2 為了減小修改複雜度,可以修改每個區間管理的範圍.傳統主席樹每個點對應的主席樹管理乙個字首...

線段樹 劃分樹 樹狀陣列

線段樹 利用陣列來維護乙個類似字首和的區間和 在查詢的時候查這個區間陣列 特殊操作 有延時標記 在區間陣列上增加基本不改變原來陣列 以達到節省時間的目的 樹狀陣列 和線段樹類似 乙個用乙個陣列維護類似字首和的東西 但 是 它維護的是乙個用二進位制表示的字首和 舉個例子 1是1 2是1 2 3是3 4...

Data 帶修改的主席樹 樹狀陣列套主席樹

樹狀陣列套主席樹 樹狀陣列的每個節點維護的是一段區間,我們將每個區間構造成一棵線段樹,這時候如果我們要修改乙個值,只需要修改logn個節點即可,時間複雜度為log 2 n 樹狀陣列維護的區間是數的個數n 離散化時是把所有數 包括要修改的數 全部離散化 1.修改 在修改之前,我們應先把序列裡原來的值在...