同步
原題鏈結
給定乙個長度為 n
nn 的陣列,q
qq 組操作:
顯然,假設你現在什麼也不會。
我們只考慮第 2
22 個操作,即先不考慮修改,如何處理區間和的詢問?
顯然,對於初始的陣列 a
ia_i
ai,只需要做乙個字首和 s
ss 使得:
s j=
∑i=1
ja
is_j = \sum_^j a_i
sj=i=
1∑j
ai
這樣,對於一組詢問:
∑ i=
lrai
=sr−
sl−1
\sum_^r a_i = s_r - s_
i=l∑r
ai=
sr−
sl−1
可以做到 o(n
)−o(
1)
\mathcal(n) - \mathcal(1)
o(n)−o
(1).
但是現在出題人加入了修改操作,你再修改的時候不得不把 s
ss 重推一遍。
這樣 o(n
)−o(
n)
\mathcal(n) - \mathcal(n)
o(n)−o
(n) 我們就完了啊。
從字首和上我們可以考慮,如何用較少的字首和記錄較多的區間答案。
乙個合法的思路是利用 rmq
\text
rmq,記:
f x,
y=∑i
=x
min(x
+2y−
1,n)
ai
f_ = \sum_^ a_i
fx,y=
i=x∑
min(x+
2y−1
,n)
ai
然後可以做到 o(n
logn)
−o(1
)\mathcal(n \log n) - \mathcal(1)
o(nlogn)
−o(1
).但是我們覺得這不好,我們用部分字首和。
即我們只記錄一部分的字首和,查詢時查詢較少一部分,修改時也只要修改較少一部分,達到複雜度的均衡。
因此,我們想到了用 lowbit
\text
lowbit
表示字首的長度。你可以理解為每次 +
++ 或 −
-− 乙個 lowbit
\text
lowbit
會在原數的二進位制中砍掉一位。
這樣,我們就可以做到 o(n
logn)
−o
(logn
)\mathcal(n \log n) - \mathcal(\log n)
o(nlogn)
−o(logn)
.這就是樹狀陣列。其實樹狀陣列的本質就是用部分字首和維護差分陣列。
時間複雜度:o(n
logn)
−o
(logn
)\mathcal(n \log n) - \mathcal(\log n)
o(nlogn)
−o(logn)
.實際得分:100pt
s100pts
100pts
#pragma gcc optimize(2)
#include
using
namespace std;
const
int n=
1e6+1;
typedef
long
long ll;
inline
intread()
int x=0;
while
(ch>=
'0'&& ch<=
'9') x=
(x<<3)
+(x<<1)
+ch-
'0',ch=
getchar()
;return x*f;
}int a[n]
; ll c[n]
;int n,m,x,y;
inline
intlowbit
(int x)
return x &
(-x);}
inline ll sum
(int x)
return s;
}inline
void
update
(int x,
int k)
}int
main()
while
(m--
)return0;
}
題解 P3374 模板 樹狀陣列 1
最簡單的zkw線段樹就十分適合這道題,為什麼用zkw線段樹,可以看一下以下精簡 我們只需要用到單點修改,區間查詢就好了。include define go i,j,n,k for int i j i n i k define fo i,j,n,k for int i j i n i k define...
題解 P3374 模板 樹狀陣列 1
恩,這是ac的第一道樹狀陣列呢。如今終於找到了折中方案 樹狀陣列!量小,還支援修改!樹狀陣列也就是二叉索引樹,又被稱為fenwick樹,然而我個人認為它不能被嚴謹地成為樹,因為充其量只是借用的樹形結構的思想,於實現上有著較大的區別。樹狀陣列雖然運用範圍沒有線段樹那麼廣,但是它的效率要高很多,比如線段...
P3374 模板 樹狀陣列 1
如題,已知乙個數列,你需要進行下面兩種操作 1.將某乙個數加上x 2.求出某區間每乙個數的和 輸入格式 第一行包含兩個整數n m,分別表示該數列數字的個數和操作的總個數。第二行包含n個用空格分隔的整數,其中第i個數字表示數列第i項的初始值。接下來m行每行包含3個整數,表示乙個操作,具體如下 操作1 ...