Files
python/TangDou/CSP-J/AcWingTraining/T1/4089_Node.cpp

94 lines
2.7 KiB
C++
Raw Normal View History

2025-08-30 18:35:01 +08:00
#include <bits/stdc++.h>
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<Node> 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;
}