第一講:基礎算法
第二講:數據結構
1.單鏈表
2.雙鏈表
3.棧
4.隊列
5.單調棧
6.單調隊列
7.KMP
8.Trie
9.並查集
10.堆
題目:
輸入一個長度為 n 的整數數列,從小到大輸出前 m 小的數。
輸入格式
第一行包含整數 n 和 m。
第二行包含 n 個整數,表示整數數列。
輸出格式
共一行,包含 m個整數,表示整數數列中前 m 小的數。
數據范圍
1≤m≤n≤105
1≤數列中元素≤109輸入樣例:
5 3 4 5 1 3 2
輸出樣例:
1 2 3
分析:

1 # 堆 2 3 堆是一個完全二叉樹。 4 5 性質:每個節點都滿足小於等於它的左右兩邊的節點。 6 7 存儲:1號節點為根節點,x的左兒子:`2x`,x的右兒子:`2x+1` 8 9 10 11 操作 12 13 把節點往下移 14 15 將根節點大於左兒子和右兒子中的最小值,將根節點與左右兒子中最小的那個交換位置。然后一直交換到不能交換為止。 16 17 ```cpp 18 void down(){ 19 20 } 21 ``` 22 23 把節點往上移 24 25 某個數變小后,每次與父節點進行比較就好了,如果比父節點小的話,就要和父節點進行交換 26 27 ```cpp 28 void up(){ 29 30 } 31 ``` 32 33 如何手寫一個堆: 34 35 1.插入一個數 36 37 2.求集合當中的最小值 38 39 3.刪除最小值 40 41 4.刪除任意一個元素 42 43 5.修改任意一個元素 44 45 46 47 1.插入一個數: 48 49 在當前堆的最后面插入進去,然后進行up操作 50 51 ```cpp 52 heap[++ size] = x; 53 54 up(size); 55 ``` 56 57 2.求集合當中的最小值 58 59 ```cpp 60 heap[1]; 61 ``` 62 63 3.刪除最小值 64 65 用堆中的最后一個元素覆蓋掉第一個元素,size--然后down一下 66 67 一維數組刪掉第一個元素比較難,但是刪掉最后一個元素很簡單 68 69 ```cpp 70 heap[1] = heap[size -- ]; 71 down(1); 72 ``` 73 74 4.刪除任意一個元素 75 76 ```cpp 77 heap[k] = heap[size]; 78 size -- ; 79 down(k), up(k); 80 ``` 81 82 5.修改任意一個元素 83 84 ```cpp 85 heap[k] = x; 86 down(k), up(k); 87 ```
代碼:

1 #include <cstdio> 2 #include <cmath> 3 4 using namespace std; 5 6 const int N = 100010; 7 8 int n, m; 9 int h[N], size; 10 11 void down(int u) 12 { 13 int t = u; 14 if ((u << 1 <= size) && h[u << 1] < h[t]) t = u << 1; 15 if ((u << 1 | 1) <= size && h[u << 1 | 1] < h[t]) t = (u << 1 | 1); 16 17 if (u != t) 18 { 19 swap(h[u], h[t]); 20 down(t); 21 } 22 } 23 int main() 24 { 25 scanf("%d%d", &n, &m); 26 size = n; 27 for (int i = 1; i <= n; i ++ ) scanf("%d", &h[i]); 28 29 for (int i = n / 2; i >= 1; i -- ) down(i); 30 31 while (m -- ) 32 { 33 printf("%d ", h[1]); 34 h[1] = h[size -- ]; 35 down(1); 36 } 37 38 return 0; 39 }
題目:
維護一個集合,初始時集合為空,支持如下幾種操作:
I x
,插入一個數 x;PM
,輸出當前集合中的最小值;DM
,刪除當前集合中的最小值(數據保證此時的最小值唯一);D k
,刪除第 k 個插入的數;C k x
,修改第 k 個插入的數,將其變為 x;現在要進行 N 次操作,對於所有第 2 個操作,輸出當前集合的最小值。
輸入格式
第一行包含整數 NN。
接下來 NN 行,每行包含一個操作指令,操作指令為
I x
,PM
,DM
,D k
或C k x
中的一種。輸出格式
對於每個輸出指令
PM
,輸出一個結果,表示當前集合中的最小值。每個結果占一行。
數據范圍
1≤N≤105
−109≤x≤109
數據保證合法。輸入樣例:
8 I -10 PM I -10 D 1 C 2 8 I 6 PM DM
輸出樣例:
-10 6
分析:
up和down操作
注意ph,hp的應用,相當於指針
ph[k] = t;第K個插入的在堆中的位置為t;
hp[t] = k;在堆中位置為t的數是第k個插入的數
代碼:

1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 5 using namespace std; 6 7 const int N = 100010; 8 9 int cnt; 10 int ph[N], hp[N];//ph是第k個插入的元素是幾,hp是當前元素是第幾個插入的 11 int h[N]; 12 13 //交換當前元素的位置 14 void heap_swap(int a, int b) 15 { 16 swap(ph[hp[a]], ph[hp[b]]); 17 swap(hp[a], hp[b]); 18 swap(h[a], h[b]); 19 } 20 21 void up(int u) 22 { 23 while (u / 2 && h[u] < h[u / 2]) 24 { 25 heap_swap(u, u / 2); 26 u >>= 1; 27 } 28 } 29 30 void down(int u) 31 { 32 int t = u; 33 if (((u << 1) <= cnt) && h[u << 1] < h[t]) t = u << 1; 34 if (((u << 1 | 1) <= cnt) && h[u << 1 | 1] < h[t]) t = (u << 1| 1); 35 if (t != u) 36 { 37 heap_swap(t, u); 38 down(t); 39 } 40 } 41 42 43 int main() 44 { 45 int n, m = 0; 46 scanf("%d", &n); 47 48 while (n -- ) 49 { 50 char op[4]; 51 int k, x; 52 scanf("%s", op); 53 if (!strcmp(op, "I")) 54 { 55 scanf("%d", &x); 56 cnt ++; 57 m ++; 58 h[cnt] = x; 59 ph[m] = cnt; 60 hp[cnt] = m; 61 up(cnt); 62 } 63 else if (!strcmp(op, "PM")) 64 { 65 printf("%d\n", h[1]); 66 } 67 else if (!strcmp(op, "DM")) 68 { 69 heap_swap(1, cnt); 70 cnt --; 71 down(1); 72 } 73 else if (!strcmp(op, "D")) 74 { 75 scanf("%d", &k); 76 k = ph[k]; 77 heap_swap(k, cnt); 78 cnt --; 79 down(k), up(k); 80 } 81 else 82 { 83 scanf("%d%d", &k, &x); 84 h[ph[k]] = x; 85 down(ph[k]), up(ph[k]); 86 } 87 } 88 89 return 0; 90 }
11.哈希表
第三講:搜索與圖論
第四講:數學知識
第五講:動態規划
第六講:貪心