可修改主席樹 樹狀陣列套主席樹

2021-08-15 02:20:59 字數 1993 閱讀 2233

普通主席樹可以查詢區間k小值,但若直接修改,則複雜度極大,而可修改主席樹通過樹狀陣列的輔助來修改,大大縮小了時間複雜度,缺點是空間複雜度過大.

修改的時間複雜度為o((logn)^2),空間複雜度為o(n*logn^2).

為了減小修改複雜度,可以修改每個區間管理的範圍.

傳統主席樹每個點對應的主席樹管理乙個字首,而可修改主席樹因為樹狀陣列在處理動態區間和上有優勢,每個點管理的範圍就是它在樹狀陣列中的管理範圍.

具體而言,在加入元素時,對所有在樹狀陣列中包含它的主席樹都進行修改,而刪除也是同乙個道理.

而再查詢時與樹狀陣列類似,樹狀陣列的查詢是log的點的相加,這裡也是一樣,log個點一起在主席樹上同時同向跳動.

log個點跳log次,故每次的複雜度為log^2.

在建樹時,為了能盡可能多的共用節點,可以先建一棵根為0,什麼都不管理的主席樹,並將所有其他主席樹的根節點先初始化為這棵主席樹的根節點,最後將元素一一加入即可.

而因為有修改操作,所以在離散化前,要先將問題儲存起來,將修改後的變數一起離散化.

(以洛谷 p2617 dynamic ranking為例)

#include

#include

#include

#include

#define c ch=getchar()

#define lb(x) (x&(-x))

#define mid ((l+r)>>1)

#define n 10010

using

namespace

std;

int m,n,size,tt,num[n],root[n],b[n*2],bb,c[n*2],jia[n],jian[n],ja,jn;

struct tree

int left,right,left_son,right_son,gs;

} tree[n*400];

struct cz

cz[n];

mapid;

void build(int now,int l,int r)

}void ad(int now,int l,int r,int u)

tree[++tt]=tree[tree[now].right_son];

tree[now].right_son=tt;

ad(tt,mid+1,r,u);

}}inline

void add(int u,int v)

}void de(int now,int u)

de(tree[now].right_son,u);

}inline

void del(int u,int v)

}int as(int u)

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

if(u<=sum)

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

return as(u);

}for(i=1; i<=ja; i++)

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

return as(u-sum);

}inline

int ask(int u,int v,int w)

for(i=v; i; i-=lb(i))

return as(w);

}inline

void check(int now)

int main()

bb=n;

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

sort(b+1,b+bb+1);

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

}root[0]=++tt;

build(tt,1,size);

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

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

// check(root[1]);

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

if(cz[i].ch=='c')

}}

可修改主席樹 樹上可修改主席樹 樹套樹套樹

題目 思路 其實樹上主席樹是把每一棵主席樹看做樹狀陣列上的乙個點,每次修改log棵主席樹,求區間和的時候同樣log查詢字首和。上 include define d while d isdigit ch getchar using namespace std const int n 2e4 5 int...

Data 帶修改的主席樹 樹狀陣列套主席樹

樹狀陣列套主席樹 樹狀陣列的每個節點維護的是一段區間,我們將每個區間構造成一棵線段樹,這時候如果我們要修改乙個值,只需要修改logn個節點即可,時間複雜度為log 2 n 樹狀陣列維護的區間是數的個數n 離散化時是把所有數 包括要修改的數 全部離散化 1.修改 在修改之前,我們應先把序列裡原來的值在...

luogu P2617 樹狀陣列套主席樹

給定乙個含有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繼續回答上面的問題。你需要編乙個這樣的程式,從輸入檔...