分析
线段树动态开点
维护n+1棵线段树,第n+1棵表示最后一行
对于不在最后一行的操作
查询第n棵线段树上的区间第k大,然后删掉,再将对应的第n+1线段树上的点删掉
插入到后面的点用一个vector来记录
对于操作在最后一行的,直接删除,再插入到vector就可以了
把删除一个点看做插入一个点,求第k大时减一下就可以了
因为最多插入k次,所以空间时间都是O(k*logn)
#include<bits/stdc++.h>
#define N 600005
#define LL long long
using namespace std;
struct Tree{int lc,rc,size;}t[N*30];
int n,m,q,Max,tot;
int rt[N];
vector<LL> S[N];
int read(){
int cnt=0;char ch=0;
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))cnt=cnt*10+(ch-'0'),ch=getchar();
return cnt;
}
void Insert(int &o,int l,int r,int pos){
if(!o) o=++tot;
t[o].size++;
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) Insert(t[o].lc,l,mid,pos);
else Insert(t[o].rc,mid+1,r,pos);
}
int Quary(int o,int l,int r,int k){
if(l==r) return l;
int mid=(l+r)>>1,sizl=mid-l+1-t[t[o].lc].size;
if(k<=sizl) return Quary(t[o].lc,l,mid,k);
else return Quary(t[o].rc,mid+1,r,k-sizl);
}
LL Delete_last(int x,LL Pos){
int pos=Quary(rt[n+1],1,Max,x);
Insert(rt[n+1],1,Max,pos);
LL ans=pos<=n ? (LL)pos*m : S[n+1][pos-n-1];
S[n+1].push_back(Pos?Pos:ans);
return ans;
}
void Solve(int x,int y){
if(y<m){
int pos=Quary(rt[x],1,Max,y);
Insert(rt[x],1,Max,pos);
LL ans=pos<m ? (LL)(x-1)*m+pos : S[x][pos-m];
S[x].push_back(Delete_last(x,ans));
printf("%lld\n",ans);
}
else printf("%lld\n",Delete_last(x,0));
}
int main(){
n=read(),m=read(),q=read();
Max=max(n,m)+q;
while(q--){
int x=read(),y=read();
Solve(x,y);
}
return 0;
}