题目描述
Sylvia 是一个热爱学习的女♂孩子。
前段时间,Sylvia 参加了学校的军训。众所周知,军训的时候需要站方阵。
Sylvia 所在的方阵中有 n × m n \times m n×m名学生,方阵的行数为 n n n,列数为 m m m。
为了便于管理,教官在训练开始时,按照从前到后,从左到右的顺序给方阵中 的学生从 1 到 n × m n \times m n×m 编上了号码(参见后面的样例)。即:初始时,第 i i i行第 j j j列 的学生的编号是 ( i − 1 ) × m + j (i-1) \times m+j (i−1)×m+j
然而在练习方阵的时候,经常会有学生因为各种各样的事情需要离队。在一天 中,一共发生了 $ q$件这样的离队事件。每一次离队事件可以用数对 ( x , y ) ( 1 ≤ x ≤ n , 1 ≤ y ≤ m ) (x,y) (1 \le x \le n, 1 \le y \le m) (x,y)(1≤x≤n,1≤y≤m)描述,表示第 x x x 行第 $y $列的学生离队。
在有学生离队后,队伍中出现了一个空位。为了队伍的整齐,教官会依次下达 这样的两条指令:
向左看齐。这时第一列保持不动,所有学生向左填补空缺。不难发现在这条 指令之后,空位在第 x x x 行第 m m m 列。
向前看齐。这时第一行保持不动,所有学生向前填补空缺。不难发现在这条 指令之后,空位在第 n n n 行第 m m m列。
教官规定不能有两个或更多学生同时离队。即在前一个离队的学生归队之后, 下一个学生才能离队。因此在每一个离队的学生要归队时,队伍中有且仅有第 n n n 行 第 m m m 列一个空位,这时这个学生会自然地填补到这个位置。
因为站方阵真的很无聊,所以 Sylvia 想要计算每一次离队事件中,离队的同学 的编号是多少。
注意:每一个同学的编号不会随着离队事件的发生而改变,在发生离队事件后 方阵中同学的编号可能是乱序的。
输入格式:
输入共 q + 1 q+1 q+1 行。
第 1 行包含 3 个用空格分隔的正整数 n , m , q n, m, q n,m,q,表示方阵大小是 n n n 行 m m m 列,一共发 生了 q q q 次事件。
接下来 q q q 行按照事件发生顺序描述了 q q q 件事件。每一行是两个整数 x , y x, y x,y用一个空 格分隔,表示这个离队事件中离队的学生当时排在第 x x x 行第 y y y 列。
输出格式:
按照事件输入的顺序,每一个事件输出一行一个整数,表示这个离队事件中离队学 生的编号。
数据保证每一个事件满足
1
≤
x
≤
n
,
1
≤
y
≤
m
1 \le x \le n,1 \le y \le m
1≤x≤n,1≤y≤m
题目分析
我们建立n+1个Splay
前
n
n
n个用来维护每行的前
m
−
1
m-1
m−1个数
还有一个用来维护最后一列
对于一个询问
(
x
,
y
)
(x,y)
(x,y)
在维护最后一列的Splay找到第
x
x
x个数并弹出
将找到的数插入第
x
x
x行Splay的末尾
在第
x
x
x行的Splay找到第
y
y
y个数并弹出
将这个数插入最后一列Splay的末尾
由于数据范围有3e5,所以还要想办法优化空间
Splay每个结点维护一个连续区间
[
l
l
,
r
r
]
[ll,rr]
[ll,rr]的数
若要弹出的数
x
x
x在某个结点内部
就把这个节点分裂成三个
[
l
l
,
x
−
1
]
,
[
x
,
x
]
,
[
x
+
1
,
r
r
]
[ll,x-1],[x,x],[x+1,rr]
[ll,x−1],[x,x],[x+1,rr]
可能本人Splay太丑 (或者是我太丑),吸了氧还是一直卡80 QAQ
哪天回头再大力卡一下常试试
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long lt;
#define RI register int
#define li inline
#define pir pair<lt,lt>
#define update(x) size[x]=size[ch[x][0]]+size[ch[x][1]]+R[x]-L[x]+1
li lt read()
{
lt x=0,f=1;
char ss=getchar();
while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
return x*f;
}
void print(lt x)
{
if(x<0){putchar('-');x=-x;}
if(x>9) print(x/10);
putchar(x%10+'0');
}
const int maxn=3000010;
lt n,m,q,cnt;
lt L[maxn],R[maxn],size[maxn];
int rt[maxn],fa[maxn],ch[maxn][2];
li void rotate(int &p,int x)
{
int y=fa[x],z=fa[y];
int d=(ch[y][0]==x);
if(y==p) p=x;
else if(ch[z][0]==y) ch[z][0]=x;
else ch[z][1]=x;
fa[y]=x; fa[ch[x][d]]=y; fa[x]=z;
ch[y][d^1]=ch[x][d]; ch[x][d]=y;
update(y); update(x);
}
li void splay(int& p,int x)
{
while(x!=p)
{
int y=fa[x],z=fa[y];
if(y!=p)
{
if((ch[y][0]==x)^(ch[z][0]==y)) rotate(p,x);
else rotate(p,y);
}
rotate(p,x);
}
}
void ins(int &p,int pa,lt num)
{
if(!p){ p=++cnt;L[p]=R[p]=num;fa[p]=pa;size[p]=1; return;}
ins(ch[p][1],p,num); update(p);
}
pir find(int p,lt k)
{
lt ss=size[ch[p][0]];
if(k<=ss) return find(ch[p][0],k);
else if(k<=ss+R[p]-L[p]+1) return make_pair(p,L[p]+k-1-ss);
else return find(ch[p][1],k-ss-(R[p]-L[p]+1));
}
li void del(int &p,int x)
{
splay(p,x);
if(ch[p][0]*ch[p][1]==0) p=ch[p][0]+ch[p][1];
else
{
int y=ch[p][1];
while(ch[y][0]) y=ch[y][0];
splay(ch[p][1],y);
fa[ch[p][0]]=y; ch[y][0]=ch[p][0];
update(y); update(p);
p=ch[p][1];
}
ch[fa[p]][0]=ch[fa[p]][1]=fa[p]=0;
}
li void split(int &p,int x,lt num)
{
splay(p,x);
if(L[p]==R[p]) del(p,x);
else if(L[p]==num) ++L[p],update(p);
else if(R[p]==num) --R[p],update(p);
else
{
L[++cnt]=num+1; R[cnt]=R[p];
size[cnt]=R[cnt]-L[cnt]+1;
R[p]=num-1;
int y=ch[p][1];
if(y){
while(ch[y][0]) y=ch[y][0];
splay(ch[p][1],y);
fa[cnt]=y,ch[y][0]=cnt;
update(y);
}
else ch[p][1]=cnt,fa[cnt]=p;
update(p);
}
}
int main()
{
n=read();m=read();q=read();
for(RI i=1;i<=n;++i)
rt[i]=++cnt,L[cnt]=(i-1)*m+1,R[cnt]=i*m-1,size[cnt]=m-1;
for(RI i=1;i<=n;++i) ins(rt[0],0,i*m),splay(rt[0],cnt);
while(q--)
{
int x=read(),y=read();
pir tt1=find(rt[0],x),tt2;
del(rt[0],tt1.first);
if(y!=m)
{
tt2=find(rt[x],y); split(rt[x],tt2.first,tt2.second);
ins(rt[x],0,tt1.second);
}
else tt2=tt1;
ins(rt[0],0,tt2.second);
print(tt2.second); putchar('\n');
}
return 0;
}