博客
关于我
1503. [NOI2004]郁闷的出纳员【平衡树-splay】
阅读量:798 次
发布时间:2023-04-16

本文共 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);}

代码解释

  • 数据结构初始化:使用MAXN定义了一个数组来存储节点信息,包括计数器、子树大小等。
  • 插入操作Insert函数将新员工插入到正确的位置,保持树的平衡。
  • 旋转操作RotateSplay函数用于保持树的平衡,确保查找和插入操作的高效性。
  • 查询操作Findx函数根据当前根节点,逐步向下调整,找到第k大的工资值。
  • 处理命令:在main函数中,逐条处理命令,更新工资调整量delta,并根据命令类型执行相应的操作。
  • 总结

    通过使用平衡二叉搜索树,我们可以高效地处理插入、删除和查询操作,确保系统在处理大量数据时依然保持高效性能。这种设计能够满足题目中的需求,确保每条命令都能被快速处理。

    转载地址:http://lsgfk.baihongyu.com/

    你可能感兴趣的文章
    MySQL 设置数据库的隔离级别
    查看>>
    MySQL 证明为什么用limit时,offset很大会影响性能
    查看>>
    Mysql 语句操作索引SQL语句
    查看>>
    MySQL 误操作后数据恢复(update,delete忘加where条件)
    查看>>
    MySQL 调优/优化的 101 个建议!
    查看>>
    mysql 转义字符用法_MySql 转义字符的使用说明
    查看>>
    mysql 输入密码秒退
    查看>>
    mysql 递归查找父节点_MySQL递归查询树状表的子节点、父节点具体实现
    查看>>
    mysql 通过查看mysql 配置参数、状态来优化你的mysql
    查看>>
    mysql 里对root及普通用户赋权及更改密码的一些命令
    查看>>
    Mysql 重置自增列的开始序号
    查看>>
    mysql 锁机制 mvcc_Mysql性能优化-事务、锁和MVCC
    查看>>
    MySQL 错误
    查看>>
    mysql 随机数 rand使用
    查看>>
    MySQL 面试题汇总
    查看>>
    MySQL 面试,必须掌握的 8 大核心点
    查看>>
    MySQL 高可用性之keepalived+mysql双主
    查看>>
    MySQL 高性能优化规范建议
    查看>>
    mysql 默认事务隔离级别下锁分析
    查看>>
    Mysql--逻辑架构
    查看>>