#include using namespace std; #define endl '\n' /* 主要注释说明: 数据结构: Node结构体:表示一个连续的相同水果块 q和q2队列:分别用于存储当前块和临时合并的块 used数组:标记水果是否已被取出 主要步骤: 初始化:将连续相同的水果合并成块 循环处理: 取出每个块的最左水果 将剩余部分放入临时队列 合并相邻的相同类型块 将合并后的块放回主队列 关键优化: 使用队列管理块,避免频繁的数组操作 通过合并相邻块减少处理次数 使用标记数组避免重复处理 这个实现通过块的管理和合并,高效地处理了水果的挑出过程,比之前的实现更加优化。 */ const int N = 200010; struct Node { // 定义块的结构体 int st, ed, th; // st:块的起始位置,ed:块的结束位置,th:块的类型(0或1) } f, x, ad; int n, cnt, t[N]; // n:水果总数,cnt:剩余水果数,t[]:存储水果序列 queue q, q2; // q:当前待处理的块队列,q2:临时存储合并后的块 bool used[N]; // 记录每个位置的水果是否已被取出 int main() { cin >> n; for (int i = 1; i <= n; i++) cin >> t[i]; // 在序列末尾添加一个与最后一个水果不同的值,方便处理边界情况 t[n + 1] = !t[n]; // 将连续相同的水果合并成块 for (int i = 2, si = 1; i <= n + 1; i++) { if (t[i] != t[i - 1]) { // 当遇到不同水果时,将之前的连续段作为一个块加入队列 q.push((Node){si, i - 1, t[si]}), si = i; } } cnt = n; // 初始化剩余水果数 while (cnt) { // 当还有水果未被取出时继续循环 // 处理当前所有块 while (q.size()) { f = q.front(); q.pop(); // 跳过已经被取出的水果 while (used[f.st] && f.st <= f.ed) f.st++; if (f.st > f.ed) continue; // 如果块已空则跳过 // 输出并标记当前块的最左水果 printf("%d ", f.st), cnt--; used[f.st] = 1; if (f.ed == f.st) continue; // 如果块中只有一个水果,取完后跳过 // 将剩余部分加入临时队列 f.st++; q2.push(f); } cout << endl; // 一个果篮处理完毕,换行 // 合并相邻的相同类型块 while (q2.size()) { ad = q2.front(); q2.pop(); // 尝试合并后续相同类型的块 while (q2.size()) { x = q2.front(); if (x.th == ad.th) { // 如果类型相同则合并 ad.ed = x.ed; q2.pop(); } else break; } q.push(ad); // 将合并后的块放回主队列 } } return 0; }