初識主席樹 Prefix XOR

2022-02-09 03:28:11 字數 3167 閱讀 1992

主席樹剛接觸覺得超強,根本看不懂,看了幾位dalao的**後終於理解了主席樹。

先看一道例題:傳送門

題目大意:

假設我們預處理出了每個數滿足條件的最右邊界。

先考慮暴力做法,直接對x~y區間暴枚,求出答案。

主席樹做法:設主席樹的下標表示邊界為i的資訊。

主席樹是一棵可持久化線段樹,可以找出線段樹的歷史版本。

主席樹的空間複雜度可以達到o((n+m)logn

)(無修改的情況下)。

因為每一次修改至多修改logn個點。

有圖為證:

對於這道題,主席樹維護的是邊界為i的總和和總共有幾個這樣的點。

注意這裡主席樹的下標(i)是這個版本邊界這個數為i。

主席樹建樹其實是對字首1~i的建樹。

因為你之前1~i-1建過樹,你建的1~i版本是在1~i-1版本的基礎上建立的。

邊界就是你之前預處理出來的邊界。

更新操作:

void updata(int l,int r,int &x,int y,long

long

v)

int mid=l+r>>1

;

if(mid>=v)updata(l,mid,t[x].l,t[y].l,v);//訪問左節點

else updata(mid+1

,r,t[x].r,t[y].r,v);//訪問右節點

t[x].sum=t[t[x].l].sum+t[t[x].r].sum;

t[x].tot=t[t[x].l].tot+t[t[x].r].tot;

}

查詢和:

long

long qsum(int l,int r,int x,int y,int ql,int

qr)//在查詢區間內

int mid=l+r>>1

;

long

long ans=0

;

if(mid>=ql)ans+=qsum(l,mid,t[x].l,t[y].l,ql,qr);

if(mid1

,r,t[x].r,t[y].r,ql,qr);

return

ans;

}

查詢區間內有多少數:

long

long qcnt(int l,int r,int x,int y,int ql,int

qr)//在查詢區間內

int mid=l+r>>1

;

long

long ans=0

;

if(mid>=ql)ans+=qcnt(l,mid,t[x].l,t[y].l,ql,qr);

if(mid1

,r,t[x].r,t[y].r,ql,qr);

return

ans;

}

all code:(被注釋的部分是暴力**)

#include #include 

using

namespace

std;

char

tc()

intread()

const

int maxn=4*1e5;

long

long n,q,seed,a[maxn+5],sum[maxn+5],p[31][2

];long

long nxt[maxn+5

];struct

nodet[maxn*40

];int root[maxn+5

],cnt;

void updata(int l,int r,int &x,int y,long

long

v)

int mid=l+r>>1

;

if(mid>=v)updata(l,mid,t[x].l,t[y].l,v);

else updata(mid+1

,r,t[x].r,t[y].r,v);

t[x].sum=t[t[x].l].sum+t[t[x].r].sum;

t[x].tot=t[t[x].l].tot+t[t[x].r].tot;

}long

long qsum(int l,int r,int x,int y,int ql,int

qr)

int mid=l+r>>1

;

long

long ans=0

;

if(mid>=ql)ans+=qsum(l,mid,t[x].l,t[y].l,ql,qr);

if(mid1

,r,t[x].r,t[y].r,ql,qr);

return

ans;

}long

long qcnt(int l,int r,int x,int y,int ql,int

qr)

int mid=l+r>>1

;

long

long ans=0

;

if(mid>=ql)ans+=qcnt(l,mid,t[x].l,t[y].l,ql,qr);

if(mid1

,r,t[x].r,t[y].r,ql,qr);

return

ans;

}int buf[90

];void printf(long

long

x)int

main()

}/*for(int i=1;i<=n;i++)

}if(!nxt[i])nxt[i]=n;

}*/for(i=1;i<=n;i++)

updata(

1,n,root[i],root[i-1

],nxt[i]);

q=read();

long

long ans=0

,qs,qc,x,y;

for(i=q;i;i--)

return0;

}

主席樹 初學

現在才開始學主席樹 弱 不過不帶修改的話 還是很簡單的嘛。或者說應該叫可持久化線段樹?首先對數的區間進行離散化,這樣下面的a i 都預設為離散化以後的結果了。對於每個1.i開乙個線段樹,對於這個線段樹中的每乙個節點 l,r 表示1.i中在 l,r 中的數的個數。顯然這n個線段樹的形態大小是完全一樣的...

主席樹 模板

思想 主席樹就是一顆持久化線段樹,為什麼叫持久化了,因為它可以儲存之前的線段樹版本,並且可以拿來用,從而優化空間.至於為什麼叫主席樹了,大概是因為發明這個演算法的人的名字的緣故吧 詳細說說 主席樹是一種離線資料結構,是由很多棵線段樹組成的。第i棵線段樹存的是前i個數的資訊 每乙個線段存數字的出現次數...

主席樹模板

維護n棵1 i的字首權值線段樹,每次查詢減一下就好了。poj 2104就是模板題,裸的靜態第k大,需要先離散化,不會的就用lower bound 多試試,研究研究應該就能懂。include include include include using namespace std const int m...