|
|
// #define LawrenceSivan
|
|
|
|
|
|
#include <bits/stdc++.h>
|
|
|
using namespace std;
|
|
|
|
|
|
typedef long long ll;
|
|
|
typedef unsigned long long ull;
|
|
|
#define re register
|
|
|
const int maxn = 3e5 + 5;
|
|
|
|
|
|
int n, m, q, now;
|
|
|
int cnt, Max;
|
|
|
|
|
|
ll ans;
|
|
|
|
|
|
struct node {
|
|
|
int ls, rs, size; // size:当前区间内有多少个数没有被标记
|
|
|
ll val;
|
|
|
|
|
|
node() {
|
|
|
}
|
|
|
node(const int _ls, const int _rs, const int _size, const ll _val) :
|
|
|
ls(_ls), rs(_rs), size(_size), val(_val) {
|
|
|
}
|
|
|
} st[maxn << 5]; // 严格来讲应该开 Q * log2(N),也就是20倍 ,为了方便与保险,我们直接开32倍
|
|
|
|
|
|
int ins[maxn], root[maxn];
|
|
|
// ins[i]记录第i棵树插入了多少个新数
|
|
|
// root[i]记录第i棵树的根节点
|
|
|
|
|
|
inline int len(int l, int r) {
|
|
|
if (now == n + 1) {
|
|
|
if (r <= n) return r - l + 1;
|
|
|
if (l <= n) return n - l + 1;
|
|
|
return 0;
|
|
|
}
|
|
|
if (r < m) return r - l + 1;
|
|
|
if (l < m) return (m - 1) - l + 1;
|
|
|
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
ll query(int &rt, int l, int r, int pos) {
|
|
|
if (!rt) { // 动态开点
|
|
|
rt = ++cnt;
|
|
|
st[rt].size = len(l, r);
|
|
|
|
|
|
if (l == r) {
|
|
|
if (now == n + 1)
|
|
|
st[rt].val = 1ll * l * m;
|
|
|
else
|
|
|
st[rt].val = 1ll * (now - 1) * m + l;
|
|
|
}
|
|
|
}
|
|
|
st[rt].size--;
|
|
|
这个区间有一个数被取出
|
|
|
if (l == r) return st[rt].val;
|
|
|
|
|
|
int mid = (l + r) >> 1;
|
|
|
if (!st[rt].ls && len(l, mid) >= pos || st[st[rt].ls].size >= pos) {
|
|
|
query(st[rt].ls, l, mid, pos);
|
|
|
} else {
|
|
|
int tmp;
|
|
|
if (!st[rt].ls)
|
|
|
tmp = len(l, mid);
|
|
|
else
|
|
|
tmp = st[st[rt].ls].size;
|
|
|
return query(st[rt].rs, mid + 1, r, pos - tmp);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void modify(int &rt, int l, int r, int pos, ll num) {
|
|
|
if (!rt) {
|
|
|
rt = ++cnt;
|
|
|
st[rt].size = len(l, r);
|
|
|
if (l == r) {
|
|
|
st[rt].val = num;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
++st[rt].size; // 这个区间末尾有一个人进去
|
|
|
if (l == r) return;
|
|
|
|
|
|
int mid = (l + r) >> 1;
|
|
|
if (pos <= mid)
|
|
|
modify(st[rt].ls, l, mid, pos, num);
|
|
|
else
|
|
|
modify(st[rt].rs, mid + 1, r, pos, num);
|
|
|
}
|
|
|
|
|
|
inline int read() {
|
|
|
int x = 0, f = 1;
|
|
|
char ch = getchar();
|
|
|
while (!isdigit(ch)) {
|
|
|
if (ch == '-') f = -1;
|
|
|
ch = getchar();
|
|
|
}
|
|
|
while (isdigit(ch)) {
|
|
|
x = x * 10 + (ch ^ 48);
|
|
|
ch = getchar();
|
|
|
}
|
|
|
return x * f;
|
|
|
}
|
|
|
|
|
|
int main() {
|
|
|
#ifdef LawrenceSivan
|
|
|
freopen("aa.in", "r", stdin);
|
|
|
freopen("aa.out", "w", stdout);
|
|
|
#endif
|
|
|
n = read();
|
|
|
m = read();
|
|
|
q = read();
|
|
|
Max = max(n, m) + q; // 一共有q次离队,于是最多有q个人再次进队,于是最大也就是队列长度加上他们本身(因为我们取出以后在位置进行标记,相当于占上了位置
|
|
|
|
|
|
while (q--) {
|
|
|
int x = read(), y = read();
|
|
|
if (y == m) { // 如果是最后一列
|
|
|
now = n + 1; // 那么一定要放到那个单独的区间里面去,也就是上面说到的蓝色区域
|
|
|
ans = query(root[now], 1, Max, x);
|
|
|
} else {
|
|
|
now = x; // 否则,那么一定在红色区域
|
|
|
ans = query(root[now], 1, Max, y);
|
|
|
}
|
|
|
|
|
|
printf("%lld\n", ans); // 输出答案
|
|
|
|
|
|
now = n + 1; // 让被选出的人进入蓝色区域的最后一个位置
|
|
|
modify(root[now], 1, Max, n + (++ins[now]), ans);
|
|
|
|
|
|
if (y != m) {
|
|
|
ans = query(root[now], 1, Max, x);
|
|
|
now = x;
|
|
|
modify(root[now], 1, Max, m - 1 + (++ins[now]), ans);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
} |