传送门
鸽了一年
测试点1-6:二维数组模拟。
测试点7-10:把所有询问到的行离散化。
测试点11-16:发现所有事件x等于1,那么每次出队,入队只会对第一行和最后一列造成影响。相当于把最后一列压到第一行,这样就相当于维护一个序列,每次找出第x个元素并放在队尾。可以用线段树维护这个序列,每个节点维护的是当前区间长度,l=r时还存了这个人的编号,当出队的时候就找到第y个人,把这段区间长度设为0,再把他放到末尾。
测试点17-20:每次出队事件,只与当前行和最后一列有关。因此,我们可以维护 n + 1 n+1 n+1棵线段树,维护当前区间长度,人的编号。前 n n n棵线段树维护 n n n行前 m − 1 m-1 m−1个人,最后一列单独用一棵线段树存。每次有人出队,就把那个人所在的区间长度-1,再查找最后一棵平衡树的第k小(即应该处于该列的人), 把他加到那一行的线段树的末尾,最后把出队的人加入最后一棵线段树末尾。
但是这样开 n + 1 n+1 n+1棵线段树会爆空间。所以采用动态开点,没有访问到的就当它不存在,访问到的时候再创建一个就好了。
#include
#include
#include
using namespace std;
typedef long long LL;
const int MAXN = 300005;
const int MAX = 10000005;
int n, m, q, now, cnt, maxl;
int rt[MAXN], ls[MAX], rs[MAX], len[MAX], pos[MAXN];
LL val[MAX], Ans;
namespace tree{
#define mid ((l + r) >> 1)
inline int calc(int l, int r){
if(now == n + 1){
if(r <= n) return r - l + 1;
if(l <= n) return n - l + 1;
}
else{
if(r <= m - 1) return r - l + 1;
if(l <= m - 1) return m - l; //(m - 1) - l + 1
}
return 0;
}
inline LL query(int &u, int l, int r, int x){
if(!u){
u = ++cnt; len[u] = calc(l, r);
if(l == r){
if(now <= n) val[u] = 1ll * (now - 1) * m + l;
else val[u] = 1ll * m * l;
}
}
len[u]--;
if(l == r) return val[u];
if(x <= len[ls[u]]) return query(ls[u], l, mid, x);
if(!ls[u] && x <= (mid - l + 1)) return query(ls[u], l, mid, x);
else{
if(!ls[u]) x -= mid - l + 1;
else x -= len[ls[u]];
return query(rs[u], mid + 1, r, x);
}
}
inline void insert(int &u, int l, int r, int x, LL k){
if(!u){
u = ++cnt; len[u] = calc(l, r);
if(l == r) val[u] = k;
}
len[u]++;
if(l == r) return;
if(x <= mid) insert(ls[u], l, mid, x, k);
else insert(rs[u], mid + 1, r, x, k);
}
#undef mid
}
inline int read(){
int k = 0; char ch = getchar();
while(ch < '0' || ch > '9') ch = getchar();
while(ch >= '0' && ch <= '9') k = k*10 + ch - '0', ch = getchar();
return k;
}
inline void print(LL x){
if(x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
int main(){
freopen("in.txt", "r", stdin);
n = read(), m = read(), q = read();
maxl = max(n, m) + q;
register int x, y;
for(int i = 1; i <= q; i++){
x = read(), y = read();
if(y == m){
now = n + 1;
Ans = tree::query(rt[now], 1, maxl, x);
}
else{
now = x;
Ans = tree::query(rt[now], 1, maxl, y);
}
print(Ans); putchar('\n');
now = n + 1; pos[now]++;
tree::insert(rt[now], 1, maxl, n + pos[now], Ans);
if(y != m){
Ans = tree::query(rt[now], 1, maxl, x);
now = x; pos[now]++;
tree::insert(rt[now], 1, maxl, m - 1 + pos[now], Ans);
}
}
return 0;
}