主席樹 單點更新 區間第k大

2021-09-20 18:30:53 字數 2270 閱讀 6129

話不多說直接寫(好像咕了好久了)----2019.5.3

主席樹又叫可持續性線段樹,它可以儲存區間各個修改時段的狀態。它通過在原樹上不斷附加單鏈來實現logn複雜度的修改和記憶,子樹間的聯絡不再是乘2或乘2加1而是通過直接存陣列下標來實現儲存(類似指標)。對不同時段的搜尋也是依靠記錄該時段根的下標來實現的。

講一下主席樹的搜尋過程:

首先確定此次要搜尋的是哪次的狀態,確定是左子樹還是右子樹,沿著它記錄的下標前進(下標可能走向任意方向),直到走到具體點為止。

#include

#include

using

namespace std;

int n,m,cnt;

//用記憶體池法建樹,用cnt輔助建

const

int maxn =

1e6+10;

struct nodeinfor[

20*maxn]

;//空間需求大

int root[maxn]

;void

build_tree

(int

&p,int l,

int r)

int mid=

(l+r)/2

;build_tree

(infor[p]

.lson,l,mid)

;//利用引用對左右子樹進行賦值

build_tree

(infor[p]

.rson,mid+

1,r);}

void

update

(int

&p,int old,

int tag,

int l,

int r,

int val)

int mid=

(l+r)/2

;if(tag<=mid)

else

}void

query

(int p,

int tag,

int l,

int r)

int mid=

(l+r)/2

;if(tag<=mid)

else

}int

main()

else

}return0;

}

#include

#include

#include

#include

using

namespace std;

const

int maxn =

1e5+10;

struct nodeinfor[

40*maxn]

;int n,m,cnt,inp[maxn]

,root[maxn]

;vector<

int> v;

intgetpos

(int a)

void

update

(int

&p,int old,

int tag,

int l,

int r)

int mid=

(l+r)/2

;if(mid>=tag)

else

}void

query

(int l,

int r,

int x,

int y,

int k)

int now=infor[infor[y]

.lson]

.sum-infor[infor[x]

.lson]

.sum;

//出現的數目

int mid=

(l+r)/2

;if(now>=k)

else

}int

main()

sort

(v.begin()

,v.end()

);v.erase

(unique

(v.begin()

,v.end()

),v.

end())

;//離散化

for(

int i=

1;i<=n;i++

)for

(int i=

0;i)return0;

}

這個部落格寫的草率只是因為我懶,而且菜,畢竟看了一天才看懂這些問題。這個部落格主要是為了自己以後查模板用,想具體學的話還是另找部落格吧。(手動狗頭)

區間第k大(主席樹)

學了一下主席樹模板題,當初看了網上的主席樹講解都沒有看懂,後面看了嗶哩嗶哩的uestc的主席樹,終於看懂了思想。每次更新的複雜度都為logn。每次更新的話就是對要更新的點路徑上的點重新更加乙個,然後進行對沒有影響的那些進行連邊。然後用乙個root記錄每乙個線段樹的根節點下標。include incl...

主席樹區間第K大

主席樹的實質其實還是一顆線段樹,然後每一次修改都通過上一次的線段樹,來新增新邊,使得每次改變就改變logn個節點,很多節點重複利用,達到節省空間的目的。1.不帶修改的區間第k大。hdu 2665 模板題 1 include2 using namespace std 3 define fopen fr...

主席樹求區間第k大

主席樹是可持久化線段樹,維護 權值個數 線段樹的字首和。相當於對每個區間 1,i 建立n顆線段樹。我們用乙個區間內的數的出現個數建線段樹,所以資料大小較大時一般進行離散化。建的是權值線段樹,即用數值作為區間,每個節點存該數出現的次數,所以query返回的其實是離散後的陣列b的下標idx,最終結果為b...