Files
python/TangDou/CSP-J/AcWingTraining/T1/4089_Node.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

94 lines
2.7 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}