https://www.luogu.com.cn/training/113#problems
【数据结构1-1】线性表
P3613 【深基15.例2】寄包柜
向量
https://www.luogu.com.cn/problem/P3613
直接开a[N][N]数组, a[100005][100005]就肯定MLE 了,
怎样设置数组才能节省内存呢?我们想到动态数组 vector
数组实现链表
P1160 队列安排
要用链表
第一次提交有部分未通过是因为可能有重复删除的数。所以要先判断是不是删过,加了判断之后AC了。
#include <bits/stdc++.h> using namespace std; typedef pair<int, int> PII; typedef long long LL; const int N = 100010; int n, m; int e[N], l[N], r[N], idx; int st[N]; //在k右边插入 void insert(int k, int x){ e[idx] = x; l[idx] = k; r[idx] = r[k]; l[r[k]] = idx; r[k] = idx; idx++; } //删除下标为k的数 void remove(int k){ r[l[k]] = r[k]; l[r[k]] = l[k]; } int main(){ cin >> n; //0是左端点,1是右端点 r[0] = 1, l[1] = 0, idx = 2; //先插入1 insert(0, 1); for(int i = 2; i <= n; i++){ int k, p; cin >> k >> p; if(p == 0) insert(l[k + 1], i); else insert(k + 1, i); } cin >> m; while(m--){ int x; cin >> x; if(!st[x]) { st[x] = 1; remove(x + 1); } } for(int i = r[0]; i != 1; i = r[i]){ printf("%d ", e[i]); } cout << endl; //printf("%.2lf", ans); return 0; }
P4387 【深基15.习9】验证栈序列
主要看思路,还有细节处理栈的情况,及时跳出、清空等。
P2234 [HNOI2002]营业额统计
直接每次往前遍历会超时。
题解思路都不常碰到,看看。
https://www.luogu.com.cn/problem/solution/P2234
【数据结构1-2】二叉树
树的遍历
P1827 [USACO3.4]美国血统 American Heritage
前序遍历中序遍历后序遍历。
二分
P5076 【深基16.例7】普通二叉树(简化版)
//upper_bound(begin,end,number)函数是求begin-end中(排好序)第一个大于 number的数
//lower_bound(begin,end,number)函数是求begin-end中(排好序)第一个大于等于 number的数
//以上两个函数传回一个指针,指针-a就是一个相对位置(所求number的下标)
这里本来自己写二分,但是WA了,没看出哪里漏了。所以直接用上面的函数,AC了。
#include <bits/stdc++.h> using namespace std; typedef pair<int, int> PII; typedef long long LL; const int N = 10010; const int INF = 0x3f3f3f3f; int n, l, r; int a[N]; int main(){ cin >> n; int cnt = 0; while(n--){ int op, x; cin >> op >> x; if(op == 1){ int l = 1, r = cnt; while(l < r){ int mid = (l + r) / 2; if(a[mid] >= x) r = mid; else l = mid + 1; } l = lower_bound(a + 1, a + cnt + 1 , x) - a; //printf("l = %d r = %d\n", l, r); cout << l << endl; } else if(op == 2){ cout << a[x] << endl; } else if(op == 3){ int l = 1, r = cnt; while(l < r){ int mid = (l + r) / 2; if(a[mid] >= x) r = mid; else l = mid + 1; } l = lower_bound(a + 1, a + cnt + 1 , x) - a; //printf("l = %d r = %d\n", l, r); if(l == 1) cout << -2147483647 << endl; else cout << a[l - 1] << endl; } else if(op == 4){ int l = 1, r = cnt; while(l < r){ int mid = (l + r + 1) / 2; if(a[mid] <= x) l = mid; else r = mid - 1; } l = upper_bound(a + 1, a + cnt + 1 , x) - a; //printf("l = %d r = %d\n", l, r); if(l == cnt + 1) cout << 2147483647 << endl; else cout << a[l] << endl; } else if(op == 5){ a[++cnt] = x; sort(a + 1, a + cnt + 1); } } //cout << ans << endl; //printf("%.2lf", ans); return 0; }
最短路径
P1364 医院设置 多种解法!
bfs floyed等最短路径问题的算法
P1229 遍历问题
思路很巧妙
LCA
P3884 [JLOI2009]二叉树问题
LCA问题,这里n小所以可以暴力,但可以了解下思路。
【数据结构1-3】集合
并查集
判断关系应用:
P1551 亲戚 普通int型
P2814 家谱 string型
分组:
P1525 [NOIP2010 提高组] 关押罪犯
参考题解用数组b[i]代表i的敌人
P1892 [BOI2003]团伙
这里也可以向上面那样开一个敌人数组
也可以使用反集
并查集+埃氏筛质数
P1621 集合
字符串哈希
P3370 【模板】字符串哈希
这里我直接偷懒用集合去重了,正常是要实现哈希这个过程,y总算法基础也有讲。
字典树Tire
P3879 [TJOI2010]阅读理解
这里我用map和set解决了,但如果题目查询次数特别多时会TLE,这时用字典树。
两种方法我都实现了
map
P3405 [USACO16DEC]Cities and States S
关键是怎么处理成对。
P5250 【深基17.例5】木材仓库
可以详细了解map的用法,begin,end,find,erase等
P4305 [JLOI2011]不重复数字
我想的是用set,但是部分TLE
解决:
改了之后还是TLE,然后把cin改为scanf,就AC了。。。。
【数据结构1-4】图的基本应用
dfs,bfs
P5318 【深基18.例3】查找文献
关键在于怎么存图,并且它的要求是从编号小的输出。
P3916 图的遍历
解决思路很巧妙,求经过的最大点,把路径反过来就是每个点能到达哪些位置,从大点开始遍历可以剪枝,因为已经到过的点不会有更大的点了。
P1113 杂务
还可以用dp,很厉害的思路!!
因为任务可以并发,所以一个任务如果有前驱的话,最优方案便是在它的最晚一个前驱结束后就立即开始,而且任务k的前驱节点一定小于k,所以读入时顺便从它的前驱里挑一个最大的转移即可。同时可以更新最终答案。
P1807 最长路
这个题我是自己按题意写的AC了,没想到用最短路的模板,可以看下题解。
P1363 幻象迷宫
用走到“同一点”作为可以到达无限远的判断标志。
拓扑排序
P1347 排序
特别多细节判断!值得一看。
#include <bits/stdc++.h> using namespace std; const int N = 30; int n, m, now; int ru[N], ruu[N], vis[N], q[N]; //q存拓扑序列 vector<int> e[N]; int tuopu(){ //1代表合法 2代表有环,3代表无法确定 int hh = 0, tt = -1; bool mul = false; //如果同时有多个入度为0的点则我们不能判断它们的大小顺序 bool uncertain = false; for(int i = 0; i < 26; i++){ ruu[i] = ru[i]; //不能影响下一次插入的判断 if(ruu[i] == 0 && vis[i]){ if(!mul) mul = true; else uncertain = true; q[++tt] = i; } } //printf("tt = %d\n", tt); if(tt == -1) return 0; //没有入度为0的点 while(hh <= tt){ int t = q[hh++]; mul = false; //重新判断 for(int i = 0; i < e[t].size(); i++){ int p = e[t][i]; ruu[p]--; if(ruu[p] == 0) { if(!mul) mul = true; else uncertain = true; q[++tt] = p; } } } //printf("tt = %d now = %d\n", tt, now); if(tt != now - 1) return 0; //有环 if(uncertain) return 2; //不确定 if(tt == n - 1) return 1; //确定 } int main(){ ios::sync_with_stdio(false); cin >> n >> m; for(int i = 0; i < m; i++){ char ch; cin >> ch; int a = ch - 'A'; if(!vis[a]) vis[a] = true, now++; cin >> ch; //'<' cin >> ch; int b = ch - 'A'; if(!vis[b]) vis[b] = true, now++; ru[b]++; e[a].push_back(b); if(tuopu() == 0) { printf("Inconsistency found after %d relations.", i + 1);//存在矛盾 return 0; } if(tuopu() == 1){ printf("Sorted sequence determined after %d relations: ", i + 1); for(int j = 0; j < n; j++){ printf("%c", q[j] + 'A'); } printf("."); return 0; } } printf("Sorted sequence cannot be determined."); return 0; }