题意:n*m个人,每次从x,y出去一个,第x行统一向左补位,第m列统一向前移位,每次输出当前位置人的编号
思路:
模拟过程很容易想到用线段树或者BIT维护+vector维护,但是不太行,于是学了动态开点,50行不压行代码。
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i,n) for(int i=0;i<n;i++)
#define for1(i,n) for(int i=1;i<=n;i++)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 3e5+5;
int n,m,q,sz,L = 1,R = 6e5+5,root[maxn];
vector<ll>a[maxn];
class dsegment_tree{public:
struct dsegment_node{
int son[2],sum;
}node[maxn*50];
int query(int k,int now,int l = L,int r = R){
if(l==r) return l;
int mid = l+r>>1,res = 0,cnt = mid-l+1-node[node[now].son[0]].sum;
if(cnt>=k) res = query(k,node[now].son[0],l,mid);
else res = query(k-cnt,node[now].son[1],mid+1,r);
return res;
}
void update(int pos,int &now,int l = L,int r = R){
if(!now) now = ++sz;node[now].sum++;
if(l==r) return;
int mid = l+r>>1;
if(pos<=mid) update(pos,node[now].son[0],l,mid);
else update(pos,node[now].son[1],mid+1,r);
}
}tree;
ll dely(int x,bool flag){
int pos = tree.query(x,root[0]);
tree.update(pos,root[0]);
ll ans = 0;
if(pos<=n) ans = 1ll*pos*m;
else ans = a[0][pos-n-1];
if(flag) a[0].push_back(ans);
return ans;
}
ll delx(int x,int y){
int pos = tree.query(y,root[x]);
tree.update(pos,root[x]);
ll ans = 0;
if(pos<m) ans = 1ll*(x-1)*m+pos;
else ans = a[x][pos-m];
a[x].push_back(dely(x,0));
a[0].push_back(ans);
return ans;
}
int main(){
IO;cin>>n>>m>>q;
forn(i,q){
int x,y;cin>>x>>y;
if(y!=m) cout<<delx(x,y)<<'
';
else cout<<dely(x,1)<<'
';
}
return 0;
}