题目

有一个 \(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)\)。可以通过。

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

const int MAXN = 3e5 + 5;

ll n, m;

struct node {
ll left, right, size;
node *child[2], *father; void updata() {size = child[0]->size + child[1]->size + right - left + 1;}
} *nul = new node; void init() {
nul->child[0] = nul->child[1] = nul->father = nul;
nul->left = 1; nul->right = nul->size = 0;
} node *newNode(ll l, ll r, node *fa) {
node *ptr = new node;
ptr->father = fa; ptr->child[0] = nul; ptr->child[1] = nul;
ptr->left = l; ptr->right = r; ptr->size = r - l + 1;
return ptr;
} void cect(node *x, node *y, ll p) {x->father = y; y->child[p] = x;}
bool getPos(node *x) {return x->father->child[1] == x;} void rotate(node *x) {
ll p = getPos(x), fp = getPos(x->father);
node *gfa = x->father->father;
cect(x->child[p ^ 1], x->father, p);
cect(x->father, x, p ^ 1); cect(x, gfa, fp);
x->child[p ^ 1]->updata(); x->updata();
} void split(node *x, ll k) {
node *tmpChild[2] = {x->child[0], x->child[1]};
if(x->left < k) {
x->child[0] = newNode(x->left, k - 1, x);
if(tmpChild[0] != nul) cect(tmpChild[0], x->child[0], 0);
x->child[0]->updata();
}
if(x->right > k) {
x->child[1] = newNode(k + 1, x->right, x);
if(tmpChild[1] != nul) cect(tmpChild[1], x->child[1], 1);
x->child[1]->updata();
}
x->left = x->right = k;
} struct splayTree {
node *rt; splayTree() {rt = newNode(1, 0, nul);} void build(node *&cur, node *fa, ll l, ll r) {
if(l <= r) {
ll mid = (l + r) >> 1;
cur = newNode(mid * m, mid * m, fa);
build(cur->child[0], cur, l, mid - 1);
build(cur->child[1], cur, mid + 1, r);
cur->updata();
}
} void splay(node *cur, node *goal) {
while(cur->father != goal) {
node *fa = cur->father, *gfa = cur->father->father;
if(gfa != goal) getPos(cur) == getPos(fa) ? rotate(fa) : rotate(cur);
rotate(cur);
}
} node *findKth(ll k) {
node *cur = rt->child[1];
while(true) {
if(k <= cur->child[0]->size) cur = cur->child[0];
else if(k > cur->child[0]->size + cur->right - cur->left + 1) {
k = k - cur->child[0]->size - (cur->right - cur->left + 1);
cur = cur->child[1];
} else {
split(cur, cur->left + k - cur->child[0]->size - 1);
splay(cur, rt);
return cur;
}
}
} ll earse(node *goal) {
node *rplNode = goal->child[0];
while(rplNode->child[1] != nul) rplNode = rplNode->child[1];
if(rplNode != nul) {
splay(rplNode, goal);
cect(rplNode, rt, 1);
cect(goal->child[1], rplNode, 1);
rplNode->updata();
} else cect(goal->child[1], rt, 1);
ll id = goal->left;
delete goal;
return id;
} void insLast(ll k) {
node *cur = rt;
while(cur->child[1] != nul) cur = cur->child[1];
if(cur != rt) splay(cur, rt);
cur->child[1] = newNode(k, k, cur);
cur->size++;
}
} row[MAXN], lastLine; ll leave(ll x, ll y) {
ll id;
if(y != m) {
lastLine.insLast(id = row[x].earse(row[x].findKth(y)));
row[x].insLast(lastLine.earse(lastLine.findKth(x)));
} else lastLine.insLast(id = lastLine.earse(lastLine.findKth(x)));
return id;
} int main() {
init();
ll q, x, y;
scanf("%lld%lld%lld", &n, &m, &q);
lastLine.build(lastLine.rt->child[1], lastLine.rt, 1, n);
for(ll i = 1; i <= n; i++)
(row[i].rt)->child[1] = newNode((i - 1) * m + 1, i * m - 1, row[i].rt);
while(q--) {
scanf("%lld%lld", &x, &y);
printf("%lld\n", leave(x, y));
}
return 0;
}

【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. java研发常见问题总结 1

    1.java中所有类的父类是什么?他都有什么方法? Object类是所有类的直接或间接基类,如果一个类在声明时未继承基类,Java就默认其基类是Object,故Object被称为根类.该类位于java ...

  2. 前端高质量知识(一)-JS内存空间详细图解

    变量对象与堆内存   var a = 20;   var b = 'abc';   var c = true;   var d = { m: 20 } 因为JavaScript具有自动垃圾回收机制,所 ...

  3. IBM区块链总经理谈区块链

    IBM区块链总经理谈区块链:3.4年前IBM的区块链人员就达到了1500人  Captain Hiro 2018-03-20 16:22 发布在 区块链 3 18349 CCN的记者Eric Eiss ...

  4. Rxjava+retrofit+mvp整合

    转载请标明出处: http://blog.csdn.net/forezp/article/details/52621898 本文出自方志朋的博客 最近在看Rxjava,写了一个简单的 demo整合了R ...

  5. runtime - 消息机制

    Xcode中使用runtime代码时,建议先做下配置: 使用runtime代码时会有适当的提醒. OC方法调用的本质是消息转发,消息机制的本质 创建一个Person类,添加方法 - (void)eat ...

  6. MySQL - Linux下安装

    本安装方式仅对5.7.21版本负责. 下载地址:wget https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.21-linux-glibc2 ...

  7. IE hack 和手机尺寸

        来自为知笔记(Wiz)

  8. windows和linux上mysql的安装

    mysql基于多平台,多版本的安装 mysql.tar.gz  链接:https://pan.baidu.com/s/1lG9BNL1mG4qbjM8xLHtrjQ 密码:s4tk MySQL 是一个 ...

  9. html之table&select不为人知的操作

    table标签和其它标签不一样,他有属性和方法! table属性: rows      可以得到table的row集合 cells      得到table所有单元格 table方法: insertR ...

  10. tcl之控制流-条件运算、条件测试、逻辑表达