基礎資料結構

22703 王培軒

講師介紹

  • 22703
  • 沒什麼特色

基礎中的基礎

前綴和

假設有陣列\(a\),定義前綴和(prefix sum)陣列\(b\)

\(b_i=\sum_{k=1}^{i}a_k\)

舉例

\(a\):1 2 3 4 5

prefix sum:1 3 6 10 15

可以幹嘛

\(O(n)\)預處理

\(O(1)\)求任意\([l,r]\)區間和

差分

假設有陣列\(a\),定義差分(differences)陣列

\(d_i=a_i-a_{i-1}\),且\(d_0=a_0\)

即可得\(a_i=\sum_{k=1}^{i}d_i\)

前綴的逆運算為差分

舉例

\(a\):1 3 6 10 15

differences:1 2 3 4 5

可以幹嘛

暫時沒有想到裸的運用><

但前綴跟差分到處都可以派上用場

待丟題

基礎線段樹

(Segment Tree)

俗話說...

任何區間題目都有一個中國人能想到線段樹的做法

我們想要解決

有長度\(n\)的陣列\(a\),\(q\)筆詢問,每次

1.詢問\([l,r]\)之區間和

2.將\(a_i\)改為\(x\)

\(n\leq 10^5,q\leq 10^5\)

暴力做太慢,用前綴和要修改也太慢...

線段樹來了

  • 完全二元樹
  • 每個節點儲存一個區間的資料
  • 兩個子樹儲存當前區間左右兩邊的資料
  • 共\(O(\log n)\)層

修改

最多修改\(O(\log n)\)個節點

Title Text

  • Bullet One
  • Bullet Two
  • Bullet Three

查詢

最多查詢\(O(\log n)\)個節點

寫法

  • 陣列型(基本款)
  • 指標型(一些比較複雜的東西會用到)
  • 偽指標型(指標型的常數改良(?)版)

陣列型

若當前節點存在\(seg[cur]\),則他的左子節點存在\(seg[cur*2]\),右子節存在\(seg[cur*2+1]\),從\(1\)開始

通常開\(seg[4*MAXN]\)

查詢、修改時遞迴處理

最好寫也最簡潔的一種

陣列型

int seg[MAXN*4];
void modify(int l,int r,int cur,int ind,int val){
	if(r-l<=1){
		seg[cur]=val;
		return;
	}
	int mid=(l+r)/2;
	if(ind<mid) modify(l,mid,cur*2,ind,val);
	else modify(mid,r,cur*2+1,ind,val);
	seg[cur]=seg[cur*2]+seg[cur*2+1];
}

int query(int l,int r,int cur,int ql,int qr){
	if(l>=qr||r<=ql) return 0;
	if(ql<=l&&qr>=r) return seg[cur];
	int mid=(l+r)/2;
	return query(l,mid,cur*2,ql,qr)+query(mid,r,cur*2+1,ql,qr);
}

它還可以維護...

  • 最大/最小值
  • XOR
  • 各種

總結

線段樹是一種將區間分塊的思想,這只是最基礎的一種應用,還有各式各樣的線段樹在等著各位。

之後資讀應該還有機會講。

BIT

What

BIT(Binary Indexed Tree),又稱Fenwick tree

這可以幹嘛

可以算是線段樹的瘦身版,\(O(\log n)\)維護前綴和

區間合則需兩個前綴和相減

Made with Slides.com