AcWing算法基础课
第一讲:基础算法
第二讲:数据结构
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.哈希表
第三讲:搜索与图论
第四讲:数学知识
第五讲:动态规划
第六讲:贪心