【队列】【利用Flag优化】简单的数据结构
https://ac.nowcoder.com/acm/contest/22669/K
小技巧
- 遍历list且最后一个元素后没有多余空格
for (auto it = mylist.begin(); it != mylist.end(); ++it) {
if (it != mylist.begin()) printf(" ");
printf("%d", *it);
}
- 学会使用rbegin() reng()反向遍历容器
rbegin() 和 end() 在使用上的主要区别在于它们迭代的方向不同。具体来说:
rbegin() 返回一个 反向迭代器,它指向容器的最后一个元素,迭代的方向是 从尾到头。
end() 返回一个 正向迭代器,它指向容器的最后一个元素的 下一个位置,迭代的方向是 从头到尾。
区别详解
rbegin() 和 rend()(反向迭代):
rbegin() 返回指向容器最后一个元素的反向迭代器,rend() 返回指向容器第一个元素之前的位置的反向迭代器。
反向迭代器使你可以从容器的最后一个元素开始向前遍历。
begin() 和 end()(正向迭代):
begin() 返回指向容器第一个元素的迭代器,end() 返回指向容器最后一个元素之后的迭代器。
正向迭代器是从容器的第一个元素开始向后遍历。
- 对于多次反转列表,考虑使用reversed标志,减少重复反转,实现“懒反转”。本题如果按部就班地反转,会超时
#include <bits/stdc++.h>
std::list<int> mylist;
bool reversed = false; // 用于记录当前的顺序是否被反转
int main() {
int n, m, a, op;
scanf("%d %d", &n, &m);
while (m--) {
scanf("%d", &op);
if (op == 1) { // 从前面插入
scanf("%d", &a);
if (reversed) {
mylist.push_back(a); // 如果当前被反转了,则从后面插入
} else {
mylist.push_front(a); // 正常顺序下从前面插入
}
} else if (op == 2) { // 从前面删除
if (reversed) {
mylist.pop_back(); // 当前被反转,从后面删除
} else {
mylist.pop_front(); // 正常顺序下从前面删除
}
} else if (op == 3) { // 从后面插入
scanf("%d", &a);
if (reversed) {
mylist.push_front(a); // 被反转后从前面插入
} else {
mylist.push_back(a); // 正常顺序下从后面插入
}
} else if (op == 4) { // 从后面删除
if (reversed) {
mylist.pop_front(); // 被反转后从前面删除
} else {
mylist.pop_back(); // 正常顺序下从后面删除
}
} else if (op == 5) { // 翻转序列
reversed = !reversed; // 只修改标志位,不真正翻转序列
} else if (op == 6) { // 输出当前元素个数和顺序
printf("%zu\n", mylist.size());
if (reversed) {
for (auto it = mylist.rbegin(); it != mylist.rend(); ++it) {
if (it != mylist.rbegin()) printf(" ");
printf("%d", *it);
}
} else {
for (auto it = mylist.begin(); it != mylist.end(); ++it) {
if (it != mylist.begin()) printf(" ");
printf("%d", *it);
}
}
printf("\n");
} else if (op == 7) { // 排序
mylist.sort(); // 直接排序,因为 list 的 sort 内部实现是稳定的 O(n log n)
if (reversed) {
mylist.reverse(); // 如果当前被反转,需要再反转回来
}
}
}
return 0;
}