話不多說直接寫(好像咕了好久了)----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...