Data 可持久化線段樹 主席樹

2022-08-09 04:27:09 字數 1250 閱讀 6588

可持久化線段樹-主席樹

節省空間;主席樹可以實現查詢區間k小的問題等;

主席樹的每個節點對應一棵線段樹,對於乙個序列,我們採用字首和的思想,如a[1],a[2],a[3],.....,每個字首建一棵線段樹,那麼就共有n棵線段樹,兩棵線段樹之差得到的就是

某個區間數字出現的次數,插入乙個值時,相當於新建一棵線段樹,在前一棵線段樹的基礎上,新建logn個節點,其餘的從前一棵線段樹那裡copy過來,線段樹里維護的是在

這n個數的序列中,排名第k的數出現的次數,若要處理區間[l,r]問題,只需要利用字首和思想,rt[r]-rt[l-1]就好了,rt[l-1]處理的是區間1-(l-1),rt[r]處理的是區間1-r,所以rt[r]-rt[l-1]處理的

就是區間l-r;

更新

首先需要建立一棵空線段樹,rt陣列裡存的是第i棵線段樹的根節點的編號,當我們插入乙個值時,只需要修改從該節點到根的一條路徑,若該節點進入線段樹右子樹,則左子樹可以共用,若進入左子樹,則右子樹可以共用,直到到達葉子節點;

查詢 區間第k[l,r]

思想為二分法,定義num=rt[now].val-rt[cmp].val,當k<=num時,直接往左子樹查詢,否則在右子樹中查詢,但注意num要減k,因為左子樹肯定小於它了,直到l==r;

luogu 3834:

#include#include

#include

using

namespace

std;

#define maxn 200009

int cnt=0,a[maxn],s[maxn],ls[maxn*20],rs[maxn*20],val[maxn*20

],rt[maxn],sz;

void build(int &p,int l,intr)}

void insert(int &p,int cmp,int x,int l,int

r)

else

}}int query(int l,int r,int l,int r,int

k)int

main()

sort(s+1,s+n+1

); sz=unique(s+1,s+n+1)-s-1

; build(rt[

0],1

,sz);

for(i=1;i<=n;i++)

for(i=1;i<=m;i++)

}

主席樹

主席樹(可持久化線段樹)

我真弱。連主席樹都不會。主席樹相當於多個線段樹,由於相鄰兩棵線段樹的節點的值只有少許不同,因此可以對於和前一棵樹一樣的子樹乙個指標指過去,無需操作,這樣每棵樹o logn 總複雜度o nlogn 以下是區間k大 include include include define n 100005 defi...

主席樹 可持久化線段樹

首先要學會普通的線段樹,然後理解權值線段樹,而主席樹就是多個權值線段樹 我自己的理解 但是這多個權值線段樹之間有公共部分,節約了空間。它一開始是乙個空樹,後來逐個添數,記錄新增的這個數在那個範圍內,並 1,顯然它每次只更新了一條鏈,其他不需要變,這樣就有了多個版本的線段樹。如果求 l,r 範圍內第k...

可持久化線段樹(主席樹)

qwq我大概又是機房最後乙個學主席樹的了吧 其實之前一直都在講 只是沒做題 做了幾道以後發現都是乙個套路qwq關鍵就是能不能看出來要用主席樹 主要可以解決 靜態 動態區間第k大 樹上也可以 一些有關區間的帶某些限制的詢問 如出現次數等 先把模板粘上來 include include include ...