可修改區間k th number

2021-07-15 03:24:49 字數 1314 閱讀 7301

這個眾所周知了。可以用主席樹實現。

具體的話其實就是開

n 棵權值線段樹,動態開節點,由於每次增加乙個點最多隻會新建lo

g2n個點,所以空間複雜度為o(

nlog

2n) 。

我們在權值線段樹上記錄該範圍數的出現次數,然後可以發現查詢的兩個區間端點的線段樹資訊可以相減,於是就可以線段樹上二分了。時間複雜度o(

nlog

2n) 。

%了一波samjia2000

注意到像上面那樣做的話,修改乙個點就要把它後面所有點也一起修改,顯然tle。

上面的方法是不能茲瓷修改的。

那我們就需要樹套樹!

我們用乙個bit,bit上的每個點都是一棵線段樹,位置為

x 的線段樹記錄了其前面lo

wbit

(x)個以bit的結構過來的點的資訊。這是一種變形的字首和。

(請注意,主席樹是真實的字首和,而用樹狀陣列則是偽字首和)

修改操作,就在bit上往後跳,跳到乙個點就改乙個點。

修改操作,就是bit套線段樹。

單次修改時間複雜度為o(

log2

2n)

o(lo

g22n

) 總的時間複雜度為o(

(n+m

)log

22n)

空間複雜度為o(

(n+m

)log

22n)

#include

#include

#define fo(i,a,b) for(int i=a;i<=b;i++)

using

namespace

std;

const

int n=10010,m=2000010;

int n,m,num,a[n],lv[n],rv[n],root[n],ls[m],rs[m],sum[m];

int lowbit(int x)

void modify(int &v,int l,int r,int x,int p)//single point modify

void add(int x,int y,int p)

void turnl()

void turnr()

int query(int l,int r,int k)//k-th number

else

}int main()

scanf("%d",&_);

while(_--)

else

}return

0;}

區間修改 區間查詢模板

如題,已知乙個數列,你需要進行下面兩種操作 1.將某區間每乙個數加上x 2.求出某區間每乙個數的和 第一行包含兩個整數n m,分別表示該數列數字的個數和操作的總個數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來m行每行包含3或4個整數,表示乙個操作,具體如下 操作1 ...

單點修改 區間求和

如題,已知乙個數列,你需要進行下面兩種操作 第一行包含兩個正整數 n,mn,m,分別表示該數列數字的個數和操作的總個數。第二行包含 nn 個用空格分隔的整數,其中第 ii 個數字表示數列第 ii 項的初始值。接下來 mm 行每行包含 33 個整數,表示乙個操作,具體如下 輸出包含若干行整數,即為所有...

樹狀陣列 區間修改,區間查詢

也許更好的閱讀體驗 好東西,以後可以不打線段樹了 本篇假定讀者都會最基礎的兩種樹狀陣列,即區改單查和單改區查 思考如何維護乙個區間的值,想到了差分 對乙個差分陣列做一次字首和可以得到每個位置的值 再對每個位置累加一下就是乙個區間的值 公式化的講,就是 設差分陣列為 c 則每個位置的值 val i s...