這個眾所周知了。可以用主席樹實現。
具體的話其實就是開
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...