1503. [NOI2004]郁闷的出纳员【平衡树-splay】
数据结构初始化:使用MAXN定义了一个数组来存储节点信息,包括计数器、子树大小等。 插入操作: 旋转操作: 查询操作: 处理命令:在
发布日期:2025-06-19 22:07:24
浏览次数:6
分类:精选文章
本文共 3746 字,大约阅读时间需要 12 分钟。
在这篇文章中,我将详细描述如何设计和实现一个高效的工资统计系统。这将帮助我们处理公司员工的工资调整和查询需求。系统将支持四种命令:新增员工、调整工资、查询工资和统计员工离开总数。由于频繁的工资调整和查询操作,我们将使用高效的数据结构来确保系统性能。
系统设计
数据结构选择
为了处理频繁的插入、删除和查询操作,我们选择使用平衡二叉搜索树(AVL树)。每个节点将存储以下信息:
- 工资值:该节点对应的员工当前工资。
- 左子树大小:左子树中的节点数。
- 右子树大小:右子树中的节点数。
- 计数器:该节点下包含的员工总数。
- 父节点:指向该节点的父节点。
- 左、右子树:指向左、右子树的节点。
员工管理
- 新增员工:使用I命令,插入一个新员工,初始工资为k-delta。如果k-delta < min,该员工离开公司,需从数据结构中删除。
- 工资调整:使用A命令增加每个员工的工资delta,使用S命令减少每个员工的工资delta。调整后,检查并删除低于min的员工。
- 工资查询:使用F命令查询第k多的工资。
代码实现
数据结构定义
#include#include #include #define MAXN 300000using namespace std;int Cnt[MAXN]; // 节点计数int Size[MAXN]; // 节点数量int Key[MAXN]; // 节点的键值int Son[MAXN][2]; // 左、右子树int Father[MAXN]; // 父节点int SIZE = 1, ROOT = 0;void Clear(int x) { Cnt[x] = Size[x] = Key[x] = 0; Son[x][0] = Son[x][1] = 0; Father[x] = 0; Update(x);}int Get(int x) { return (Son[Father[x]][1] == x);}void Update(int x) { if (x == 0) return; Size[x] = Cnt[x]; if (Son[x][1]) Size[x] += Size[Son[x][1]]; if (Son[x][0]) Size[x] += Size[Son[x][0]];}void Rotate(int x) { int fa = Father[x]; int fafa = Father[fa]; int wh = Get(x); Son[fa][wh] = Son[x][wh ^ 1]; Father[fa] = x; if (Son[fa][wh]) Father[Son[fa][wh]] = fa; Father[x] = fafa; Son[x][wh ^ 1] = fa; if (fafa) Son[fafa][Son[fafa][1] == fa] = x; Update(fa); Update(x);}void Splay(int x) { for (int fa = Father[x]; fa; Rotate(x)) { if (Father[fa]) Rotate(Get(fa) == Get(x) ? fa : x); } ROOT = x;}int Findx(int k) { int now = ROOT; while (true) { if (k > Size[Son[now][0]]) { now = Son[now][0]; } else { k -= Size[Son[now][0]]; if (k <= Cnt[now]) { Splay(now); return Key[now]; } k -= Cnt[now]; now = Son[now][1]; } }}void Insert(int x) { if (ROOT == 0) { ROOT = SIZE++; Key[ROOT] = x; Cnt[ROOT] = Size[ROOT] = 1; return; } int now = ROOT, fa = 0; while (true) { if (Key[now] == x) { Cnt[now]++; Update(now); Splay(now); return; } fa = now; now = Son[now][x > Key[now]]; if (now == 0) { SIZE++; Key[SIZE] = x; Cnt[SIZE] = Size[SIZE] = 1; Father[SIZE] = fa; Son[fa][x > Key[fa]] = SIZE; Update(fa); Splay(SIZE); return; } }}int main() { int delta = 0, n, min, x, Sum = 0, Ans = 0; char p; scanf("%d %d", &n, &min); for (int i = 1; i <= n; ++i) { Insert(min - delta - 1); Sum += Size[Son[ROOT][0]] + Cnt[ROOT] - 1; Ans += Size[Son[ROOT][0]] + Cnt[ROOT] - 1; int old_root = ROOT; Father[Son[ROOT][1]] = 0; ROOT = Son[ROOT][1]; Clear(old_root); scanf("%c %d", &p, &x); if (p == 'A') delta += x; else if (p == 'S') delta -= x; else if (p == 'I') { if (x - delta >= min - delta) { Insert(x - delta); Sum++; } } else if (p == 'F') { if (Sum >= x) { int pos = Sum - x + 1; if (pos > Cnt[ROOT]) { printf(-1); } else { int res = Findx(pos); printf(res + delta); } } else { printf(-1); } } } printf(Ans);}
代码解释
Insert函数将新员工插入到正确的位置,保持树的平衡。Rotate和Splay函数用于保持树的平衡,确保查找和插入操作的高效性。Findx函数根据当前根节点,逐步向下调整,找到第k大的工资值。main函数中,逐条处理命令,更新工资调整量delta,并根据命令类型执行相应的操作。总结
通过使用平衡二叉搜索树,我们可以高效地处理插入、删除和查询操作,确保系统在处理大量数据时依然保持高效性能。这种设计能够满足题目中的需求,确保每条命令都能被快速处理。
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2026年06月18日 15时38分00秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
PHP手机号码归属地查询API接口
2023-03-01
PHP执行耗时脚本实时输出内容
2023-03-01
PHP扩展安装
2023-03-01
PHP扩展数据库连接参数说明详解
2023-03-01
php把get参数放入数组_php怎么将数组转为url参数?
2023-03-01
PHP投票小程序
2023-03-01
php拆分数组不改变key值
2023-03-01
php接口返回数据 用echo 还是return?
2023-03-01
php接口返回状态,大家一般怎么规范接口返回内容
2023-03-01
php接收formdata上传的多个文件,使用formData()上传多个文件
2023-03-01
PHP操作csv文件导入+导出
2023-03-01
php操作mysql用select_php如何操作mysql获取select 结果
2023-03-01
PHP操作符与控制结构
2023-03-01
PHP支付宝SDK使用,电脑网页支付
2023-03-01
php支付宝手机网页支付类实例
2023-03-01
PHP改变数组key值的方法
2023-03-01
php教程之php空白页的原因及解决方法
2023-03-01
PHP数据库操作
2023-03-01
PHP数据文件过大,导致PHP加速器eaccelerator在PHP5.2版本下崩溃
2023-03-01
RabbitMQ - 死信、TTL原理、延迟队列安装和配置
2023-03-01