樹狀陣列套主席樹
樹狀陣列的每個節點維護的是一段區間,我們將每個區間構造成一棵線段樹,這時候如果我們要修改乙個值,只需要修改logn個節點即可,
時間複雜度為log^2(n),樹狀陣列維護的區間是數的個數n;離散化時是把所有數(包括要修改的數)全部離散化;
1.修改
在修改之前,我們應先把序列裡原來的值在主席樹對應節點+1(主席樹里維護的是某個數出現的次數),遍歷logn棵主席樹。在修改時,先把該
數原來的值的在主席樹上的對應節點+(-1),再把要修改的值在對應節點+1,並在原陣列上修改;
2.查詢區間k大
其實查詢和普通主席樹在原理上並沒有什麼區別,都是用二分,然後樹套樹就是把乙個區間的主席樹拆成了若干部分,(由樹狀陣列來完成),
例:我們要查詢區間[l,r]第k大,用乙個陣列來記錄從1到l要經過的每棵主席樹的根節點,再用另乙個陣列來記錄從1到r要經過的每棵主席樹的
根節點,利用字首和思想,在查詢時先把第乙個陣列的值的sum累加起來,另乙個也一樣,兩個陣列作差,得到的就是區間l到r的數出現的個數,
然後再用二分不斷縮小範圍,直至l==r;
luogu 2617:
1 #include2 #include3 #include4view code#define lowbit(x) x&-x
5using
namespace
std;
6#define maxn 10005
7int totn=0,cnt=0,a[maxn*2],s[maxn<<1],ls[maxn*600],rs[maxn*600],val[maxn*600],rt[maxn*600],sz=0,ca[maxn*2],cb[maxn*2
],totx,toty,n,xx[maxn],yy[maxn],cc[maxn];8//
void build(int &p,int l,int r)
15//}16
void insert(int &p,int cmp,int x,int l,int r,int
v)23
else26}
27}28int query(int l,int r,int
k)38
else42}
43void add(int x,int
v)47
intread()
55return
s;56}57
intmain()
5866
for(i=1;i<=m;i++)74}
75 sort(s+1,s+totn+1
);76 sz=unique(s+1,s+totn+1)-s-1;77
for(i=1;i<=n;i++)
78 add(i,1
);79
//build(rt[0],1,sz);
80//
for(i=1;i<=n;i++)
83//
for(i=1;i<=m;i++)
87for(i=1;i<=m;i++)
95else
100}
101 }
可修改主席樹 樹狀陣列套主席樹
普通主席樹可以查詢區間k小值,但若直接修改,則複雜度極大,而可修改主席樹通過樹狀陣列的輔助來修改,大大縮小了時間複雜度,缺點是空間複雜度過大.修改的時間複雜度為o logn 2 空間複雜度為o n logn 2 為了減小修改複雜度,可以修改每個區間管理的範圍.傳統主席樹每個點對應的主席樹管理乙個字首...
帶修改的主席樹
對於單點修改的主席樹,我們可以採用樹套樹來寫,原因 不會整體二分求帶修改的區間第k小。所以學習了一波 待修改的主席樹。真的是難寫,或者說碼量有點大。不過和三維偏序cdq分治相比其實差不了多少,但是cdq終究比樹套樹快而且空間消耗小。兩者都很不錯!經典題,但是對於我這個根本不懂樹套樹的人來說是有點難度...
樹狀陣列套主席樹 帶修改區間K大數
題目描述 給定乙個含有n個數的序列a 1 a 2 a 3 a n 程式必須回答這樣的詢問 對於給定的i,j,k,在a i a i 1 a i 2 a j 中第k小的數是多少 1 k j i 1 並且,你可以改變一些a i 的值,改變後,程式還能針對改變後的a繼續回答上面的問題。你需要編乙個這樣的程式...