博客
关于我
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中floor函数的作用是什么?
    查看>>
    MySQL中group by 与 order by 一起使用排序问题
    查看>>
    mysql中having的用法
    查看>>
    MySQL中interactive_timeout和wait_timeout的区别
    查看>>
    mysql中int、bigint、smallint 和 tinyint的区别、char和varchar的区别详细介绍
    查看>>
    mysql中json_extract的使用方法
    查看>>
    mysql中json_extract的使用方法
    查看>>
    mysql中kill掉所有锁表的进程
    查看>>
    mysql中like % %模糊查询
    查看>>
    MySql中mvcc学习记录
    查看>>
    mysql中null和空字符串的区别与问题!
    查看>>