题目

有一个 \(n\times m\) 的方阵,每次出来一个人后向左看齐,向前看齐,询问每次出来的人的编号。

\(n\le 3\times 10^5\)

分析

我们考虑离队本质上只有两种操作:

  • 删除
  • 放入末尾

发现这显然可以用平衡树处理,这里我选用Splay。

需要注意的是,空间不可能开到 \(9\times 10^{10}\),只能动态开点,发现队列总是有大部分是连续的编号,所以每个节点储存一个标号范围,若需要访问到中间的标号 \(k\),将该节点分裂成三个节点\([l,k - 1],\ [k, k],\ [k + 1, r]\)即可。

时间复杂度 \(\Theta(n\log n)\),空间复杂度 \(\Theta(n\log n)\)。可以通过。

代码

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int MAXN = 3e5 + 5;
  5. ll n, m;
  6. struct node {
  7. ll left, right, size;
  8. node *child[2], *father;
  9. void updata() {size = child[0]->size + child[1]->size + right - left + 1;}
  10. } *nul = new node;
  11. void init() {
  12. nul->child[0] = nul->child[1] = nul->father = nul;
  13. nul->left = 1; nul->right = nul->size = 0;
  14. }
  15. node *newNode(ll l, ll r, node *fa) {
  16. node *ptr = new node;
  17. ptr->father = fa; ptr->child[0] = nul; ptr->child[1] = nul;
  18. ptr->left = l; ptr->right = r; ptr->size = r - l + 1;
  19. return ptr;
  20. }
  21. void cect(node *x, node *y, ll p) {x->father = y; y->child[p] = x;}
  22. bool getPos(node *x) {return x->father->child[1] == x;}
  23. void rotate(node *x) {
  24. ll p = getPos(x), fp = getPos(x->father);
  25. node *gfa = x->father->father;
  26. cect(x->child[p ^ 1], x->father, p);
  27. cect(x->father, x, p ^ 1); cect(x, gfa, fp);
  28. x->child[p ^ 1]->updata(); x->updata();
  29. }
  30. void split(node *x, ll k) {
  31. node *tmpChild[2] = {x->child[0], x->child[1]};
  32. if(x->left < k) {
  33. x->child[0] = newNode(x->left, k - 1, x);
  34. if(tmpChild[0] != nul) cect(tmpChild[0], x->child[0], 0);
  35. x->child[0]->updata();
  36. }
  37. if(x->right > k) {
  38. x->child[1] = newNode(k + 1, x->right, x);
  39. if(tmpChild[1] != nul) cect(tmpChild[1], x->child[1], 1);
  40. x->child[1]->updata();
  41. }
  42. x->left = x->right = k;
  43. }
  44. struct splayTree {
  45. node *rt;
  46. splayTree() {rt = newNode(1, 0, nul);}
  47. void build(node *&cur, node *fa, ll l, ll r) {
  48. if(l <= r) {
  49. ll mid = (l + r) >> 1;
  50. cur = newNode(mid * m, mid * m, fa);
  51. build(cur->child[0], cur, l, mid - 1);
  52. build(cur->child[1], cur, mid + 1, r);
  53. cur->updata();
  54. }
  55. }
  56. void splay(node *cur, node *goal) {
  57. while(cur->father != goal) {
  58. node *fa = cur->father, *gfa = cur->father->father;
  59. if(gfa != goal) getPos(cur) == getPos(fa) ? rotate(fa) : rotate(cur);
  60. rotate(cur);
  61. }
  62. }
  63. node *findKth(ll k) {
  64. node *cur = rt->child[1];
  65. while(true) {
  66. if(k <= cur->child[0]->size) cur = cur->child[0];
  67. else if(k > cur->child[0]->size + cur->right - cur->left + 1) {
  68. k = k - cur->child[0]->size - (cur->right - cur->left + 1);
  69. cur = cur->child[1];
  70. } else {
  71. split(cur, cur->left + k - cur->child[0]->size - 1);
  72. splay(cur, rt);
  73. return cur;
  74. }
  75. }
  76. }
  77. ll earse(node *goal) {
  78. node *rplNode = goal->child[0];
  79. while(rplNode->child[1] != nul) rplNode = rplNode->child[1];
  80. if(rplNode != nul) {
  81. splay(rplNode, goal);
  82. cect(rplNode, rt, 1);
  83. cect(goal->child[1], rplNode, 1);
  84. rplNode->updata();
  85. } else cect(goal->child[1], rt, 1);
  86. ll id = goal->left;
  87. delete goal;
  88. return id;
  89. }
  90. void insLast(ll k) {
  91. node *cur = rt;
  92. while(cur->child[1] != nul) cur = cur->child[1];
  93. if(cur != rt) splay(cur, rt);
  94. cur->child[1] = newNode(k, k, cur);
  95. cur->size++;
  96. }
  97. } row[MAXN], lastLine;
  98. ll leave(ll x, ll y) {
  99. ll id;
  100. if(y != m) {
  101. lastLine.insLast(id = row[x].earse(row[x].findKth(y)));
  102. row[x].insLast(lastLine.earse(lastLine.findKth(x)));
  103. } else lastLine.insLast(id = lastLine.earse(lastLine.findKth(x)));
  104. return id;
  105. }
  106. int main() {
  107. init();
  108. ll q, x, y;
  109. scanf("%lld%lld%lld", &n, &m, &q);
  110. lastLine.build(lastLine.rt->child[1], lastLine.rt, 1, n);
  111. for(ll i = 1; i <= n; i++)
  112. (row[i].rt)->child[1] = newNode((i - 1) * m + 1, i * m - 1, row[i].rt);
  113. while(q--) {
  114. scanf("%lld%lld", &x, &y);
  115. printf("%lld\n", leave(x, y));
  116. }
  117. return 0;
  118. }

【NOIP 2017 提高组】列队的更多相关文章

  1. NOIP 2017 提高组 day1t2 时间复杂度

    P3952 时间复杂度 标签 NOIp提高组 2017 时空限制 1000ms / 128MB 小明正在学习一种新的编程语言 A++,刚学会循环语句的他激动地写了好多程序并 给出了他自己算出的时间复杂 ...

  2. NOIP 2008提高组第三题题解by rLq

    啊啊啊啊啊啊今天已经星期三了吗 那么,来一波题解吧 本题地址http://www.luogu.org/problem/show?pid=1006 传纸条 题目描述 小渊和小轩是好朋友也是同班同学,他们 ...

  3. [NOIp 1998 提高组]Probelm 2 连接多位数【2011百度实习生笔试题】

    /*====================================================================== [NOIp 1998 提高组]Probelm 2 连接 ...

  4. NOIP 2014 提高组 题解

    NOIP 2014 提高组 题解 No 1. 生活大爆炸版石头剪刀布 http://www.luogu.org/problem/show?pid=1328 这是道大水题,我都在想怎么会有人错了,没算法 ...

  5. NOIP 2001 提高组 题解

    NOIP 2001 提高组 题解 No 1. 一元三次方程求解 https://vijos.org/p/1116 看见有人认真推导了求解公式,然后猥琐暴力过的同学们在一边偷笑~~~ 数据小 暴力枚举即 ...

  6. 最优贸易 NOIP 2009 提高组 第三题

    题目描述 C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个 城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分 为双向通行的道路 ...

  7. NOIP 2006 提高组 t1 能量项链

    题目描述 在Mars星球上,每个Mars人都随身佩带着一串能量项链.在项链上有N颗能量珠.能量珠是一颗有头标记与尾标记的珠子,这些标记对应着某个正整数.并且,对于相邻的两颗珠子,前一颗珠子的尾标记一定 ...

  8. [NOIp2017提高组]列队

    [NOIp2017提高组]列队 题目大意 一个\(n\times m(n,m\le3\times10^5)\)的方阵,每个格子里的人都有一个编号.初始时第\(i\)行第\(j\)列的编号为\((i-1 ...

  9. noip 2014 提高组初赛

    noip 2014 提高组初赛 一. TCP协议属于哪一层协议( ) A. 应用层 B. 传输层 C. 网络层 D. 数据链路层 B TCP(传输控制协议) 若有变量int a; float: x, ...

随机推荐

  1. nodejs一个函数实现消息队列中间件

    消息队列中间件(Message Queue)相信大家不会陌生,如Kafka.RabbitMQ.RocketMQ等,已经非常成熟,在大大小小的公司和项目中也已经广泛使用. 有些项目中,如果是只使用初步的 ...

  2. Selenium入门17 selenium IDE安装及使用

    selenium IDE是firefox浏览器的一个插件,支持脚本的录制回放,关键字驱动的.界面跟robotframework很像. 实际测试中不用录制回放,不过初学者拿来看看元素是如何定位的还是有用 ...

  3. SQL:获取语句执行时间2

    获取sql执行时间方法2 --清除缓存 CHECKPOINT; DBCC DROPCLEANBUFFERS; DBCC FREEPROCCACHE; DBCC FREESYSTEMCACHE ('AL ...

  4. QT学习之QScript

    QT中有解析Json的一个类叫QScript.貌似还有一个QJson,但听说解析的方便性不如QScript,具体没有深入探究,这里仅简单记录一下QScript的使用. 首先,主要使用到的类有QScri ...

  5. 20145238-荆玉茗 《Java程序设计》第4周学习总结

    20145238 <Java程序设计>第4周学习总结 教材学习内容总结第六章 继承与多态 6.1.1 ·继承基本上就是避免多个类间重复定义共同行为. 在游戏中会有很多程序代码重复的片段,这 ...

  6. python中的for循环如何控制步长

    for i in range(开始/左边界, 结束/右边界, 步长): print i 例如 for i in range(1, 10, 2): print i 等价于 for (i=1;i<= ...

  7. Ubuntu 12.04 the system is running in low-graphics mode

    1.出现问题如图所示: 2.解决方案: Ctrl + Alt + F1 df -h 输入密码,到了这一步,也是可以使用terminal,那么没有图形界面也是可以的 cd /etc/X11 sudo c ...

  8. 【洛谷P1090】合并果子

    合并果子 题目链接 贪心:每次先合并最小的两堆果子 用堆实现 #include<iostream> #include<cstdio> using namespace std; ...

  9. centos安装django

    1.如果默认安装的是python2.6,先升级至python2.7 参考:http://www.cnblogs.com/tiger2soft/p/5677843.html 2.安装pip 先下载get ...

  10. Ecliplse 重命名后web.xml 报错Attribute "xmlns" was already specified for element "web-app".

      报错信息:Attribute "xmlns" was already specified for element "web-app" 由于项目的重命名,出现 ...