题解:P12166 [蓝桥杯 2025 省 C/Java A/研究生组] 冷热数据队列
思路
直接模拟。我不会写工程化代码。
考虑使用 list 模拟两个队列,不用 deque 一个原因是常数太大,另一个原因是貌似不支持删除中间元素。
操作一
若 \(p\) 不在队列 \(q\) 中(即既不在 \(q_1\) 中,也不在 \(q_2\) 中),则加载数据页 \(p\),并插入到 \(q_2\) 的首部。
我们考虑开一个 bitset 或者 bool 数组 \(vis\) 来记录对于某个 \(p\) 其是否在队列中。若 \(vis_i=0\),则在 \(q_2\) 的头部插入元素 \(p\),同时更新 \(vis_i\)。
当然,为了后面的淘汰元素考虑,我们可以开一个桶存储元素所在的队列和其所在位置的迭代器。
实现
if(vis[x])
{
// ...
}
else
{
vis[x]=1;
qb.push_front(x);
_Mp[x]=make_pair(2,qb.begin());
}
操作二
若 \(p\) 已经在队列 \(q\) 中,则将 \(p\) 移动至 \(q_1\) 首部。
这时候我们前面记录的 \(vis\) 又起作用了。若 \(vis_i=1\),找到桶中记录的 \(p\) 所在的队列和指向 \(p\) 的迭代器,利用 erase 删除即可,删除迭代器貌似是 \(O(1)\) 的。最好不要使用 remove。
删除后重新将 \(p\) 加入至 \(q_1\) 首部,此时和操作一中的步骤类似,记录下 \(p\) 所在的队列和其所在位置的迭代器。由于 \(vis_i\) 已经等于 \(1\),无需再更新。
实现
if(vis[x])
{
auto tmp=_Mp[x];
if(tmp.first==1)
qa.erase(tmp.second);
else
qb.erase(tmp.second);
qa.push_front(x);
_Mp[x]=make_pair(1,qa.begin());
}
操作三
当 \(q_1\) 或 \(q_2\) 队列容量不足时,会将其尾部的数据页淘汰出去。
和操作四一起实现。
操作四
当 \(q_1\) 已满,但 \(q_2\) 未满时,从 \(q_1\) 中淘汰出的数据页会移动到 \(q_2\) 首部。
由于 \(q_1\) 淘汰的元素会移动到 \(q_2\),不妨考虑先淘汰 \(q_1\) 中的元素,若加入 \(q_2\) 后导致 \(q_2\) 满了,再淘汰 \(q_2\) 中的最后一个元素。list 自带 rbegin 返回指向最后一个元素的迭代器。
同样地,记录元素所在的队列及指向这个元素的迭代器,注意 \(q_2\) 淘汰的元素的 \(vis\) 值应当变为 \(0\)。
实现
if(qa.size()>na)
{
auto tmp=*qa.rbegin();
qb.push_front(tmp);
_Mp[tmp]=make_pair(2,qb.begin());
qa.pop_back();
}
if(qb.size()>nb)
{
auto tmp=*qb.rbegin();
vis[tmp]=0;
qb.pop_back();
}
输出
遍历两个链表即可。
实现
for(auto i:qa)
printf("%d ",i);
printf("\n");
for(auto i:qb)
printf("%d ",i);
printf("\n");
代码
算上我又臭又长的缺省源总共六十多行。非常好写。
#include <bits/stdc++.h>
//#include <bits/extc++.h>
//#define int long long
#define __MULTITEST__
#undef __MULTITEST__
using namespace std;
//using namespace __gnu_cxx;
//using namespace __gnu_pbds;
int na,nb,m;
list<int> qa,qb;
bitset<100005> vis;
pair<int,list<int>::iterator> _Mp[100005];
signed main()
{
#ifdef __MULTITEST__
signed T;
scanf("%d",&T);
while(T--)
{
#endif
scanf("%d%d%d",&na,&nb,&m);
for(int i=1;i<=m;i++)
{
int x;
scanf("%d",&x);
if(vis[x])
{
auto tmp=_Mp[x];
if(tmp.first==1)
qa.erase(tmp.second);
else
qb.erase(tmp.second);
qa.push_front(x);
_Mp[x]=make_pair(1,qa.begin());
}
else
{
vis[x]=1;
qb.push_front(x);
_Mp[x]=make_pair(2,qb.begin());
}
if(qa.size()>na)
{
auto tmp=*qa.rbegin();
qb.push_front(tmp);
_Mp[tmp]=make_pair(2,qb.begin());
qa.pop_back();
}
if(qb.size()>nb)
{
auto tmp=*qb.rbegin();
vis[tmp]=0;
qb.pop_back();
}
}
for(auto i:qa)
printf("%d ",i);
printf("\n");
for(auto i:qb)
printf("%d ",i);
printf("\n");
#ifdef __MULTITEST__
}
#endif
return 0;
}

浙公网安备 33010602011771号