AcWing 4089. 小熊的果篮-队列模拟
原题链接
困难
作者:
ywt51
,
2024-11-08 11:10:42
,
所有人可见
,
阅读 2
算法1:队列模拟- $O()$
//队列维护出每一块,以及如果两块相邻,且块元素一样,合并连通起来的块,
#include <bits/stdc++.h>
using namespace std;
const int N = 2E5+10;
int n, a[N];
struct node{
int st, ed, w;
};
bool vis[N]; //标记对应编号位置的东西是否取走了
queue<node> q, tmp;
int main()
{
cin >> n;
for (int i = 1; i <= n; ++ i) cin >> a[i];
a[n+1] = !a[n]; //边界
for (int i = 2, left = 1; i <= n+1; ++ i)
if (a[i] != a[i-1])
{
q.push({left, i-1, a[i-1]}); //前一段相同的合并起来
left = i;
}
int cnt = n; //水果数量
while (cnt)
{
//从当前的还未取完的 每个块中取出头
while (q.size())
{
auto t = q.front(); q.pop();
while (t.st <= t.ed && vis[t.st]) t.st++; //找到该块第一个没取走的
if (t.st > t.ed) continue; //这一块中都取完了
//否则没有取完 至少有一个可以取
cout << t.st << ' ';
cnt--;
vis[t.st] = 1;
t.st++;
if (t.st > t.ed) continue; //取完 不加入后序的块中
tmp.push(t); //加入到tmp队列中
}
cout << endl;
//合并一下可以合并的 块
while (tmp.size())
{
auto t = tmp.front(); tmp.pop();
while (tmp.size())
{
auto x = tmp.front();
if (x.w == t.w)
{
t.ed = x.ed;
tmp.pop(); //x合并到t上 更新t的右端点,
}
else break; //合并不到t上,t独立在进入q
}
q.push(t); //走出循环 把t在重新放回q中
}
}
return 0;
}