P11043 [蓝桥杯 2024 省 Java B] 分布式队列 题解
题目传送门:P11043 分布式队列
一、题目描述
分布式队列包含 N 个节点(编号 0 至 N-1 ,0 号为主节点),主节点负责添加元素,副节点负责同步主节点的队列。元素只有在被所有节点同步后才具有可见性。需要处理三种操作:
add element
:主节点添加元素sync follower_id
:指定副节点同步下一个缺失元素query
:查询当前具有可见性的元素数量
二、题目分析
这道题模拟了一个分布式队列的同步过程,关键在于理解"可见性"的定义:一个元素只有在被所有节点(包括主节点和所有副节点)同步后才是可见的。
三、解题思路
- 使用数组
a
维护每个节点的队列状态 add
操作只在主节点(0号节点)的队列末尾添加元素sync
操作让指定副节点同步主节点的下一个元素query
操作时,找到所有副节点中最小的队列长度,这就是已完全同步的元素数量
四、算法讲解
算法:模拟算法
原理:
- 主节点维护完整队列
- 每个副节点通过
sync
操作逐步同步主节点的元素 - 可见元素数量由"木桶效应"决定,即所有副节点中同步最慢的那个
实现步骤:
- 初始化N个节点的队列
- 处理每个操作:
add
:主节点队列追加元素sync
:副节点从主节点同步下一个元素query
:计算所有副节点最小队列长度
例子 :
如样例中,当所有节点都同步了前3个元素时,query结果为3。
五、代码实现
cpp
#include <bits/stdc++.h>
using namespace std;
// #define int long long
const int N = 12;
void solve()
{
int n;
cin >> n;
vector<vector<int>> a(n); // 每个节点的队列
string s;
while (cin >> s)
{
int x;
if (s == "add")
{
cin >> x;
a[0].push_back(x); // 只在主节点添加元素
}
else if (s == "sync")
{
cin >> x;
int len = a[x].size();
a[x].push_back(a[0][len]); // 副节点同步主节点的下一个元素
}
else // query操作
{
if (n == 1) // 只有主节点特殊情况
{
cout << a[0].size() << "\n";
continue;
}
int len = 1e9;
for (int i = 1; i < n; i++) // 找所有副节点最小队列长度
{
len = min(len, (int)a[i].size());
}
cout << len << "\n";
}
}
}
signed main()
{
// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
solve();
return 0;
}
六、重点细节
- 可见性判断:一个元素在所有节点中都存在才算可见,因此取所有副节点队列长度的最小值
- 边界情况:当N=1时(只有主节点),所有添加的元素都立即可见
- 同步顺序:副节点按顺序同步主节点的元素,不能跳过
七、复杂度分析
- 时间复杂度:O(q*N),q是操作数,N是节点数。每个query需要遍历所有副节点。
- 空间复杂度:O(q),最坏情况下所有操作都是add,主节点需要存储所有元素。
八、总结
这道题通过模拟分布式队列的同步过程,考察了对队列操作和同步机制的理解。关键点在于正确维护每个节点的队列状态,并在查询时正确计算已被所有节点同步的元素数量。