题目
很厉害的一道题。
首先考虑
x
=
1
x=1
x=1 的特殊性质。也就是每一次操作就是对
(
1
,
y
)
⋯
(
1
,
m
−
1
)
+
(
1
,
m
)
⋯
(
n
,
m
)
(1,y)\cdots(1,m-1)+(1,m)\cdots(n,m)
(1,y)⋯(1,m−1)+(1,m)⋯(n,m) 的区间循环位移。考虑到可能成为答案的数很少,用 BIT + 二分 维护第一行。具体地,如果一个数存在,那么在 BIT 中该位置的等于
1
1
1,否则等于
0
0
0。然后二分第
k
k
k 个数的位置也就是
q
u
e
r
y
(
p
o
s
)
=
k
query(pos)=k
query(pos)=k 的位置。
现在考虑正解。因为对于操作
(
x
,
y
)
(x,y)
(x,y),会影响的格子只有
(
x
,
y
)
→
(
x
,
m
−
1
)
(x,y)\rightarrow (x,m-1)
(x,y)→(x,m−1) 和
(
x
,
m
)
→
(
n
,
m
)
(x,m)\rightarrow (n,m)
(x,m)→(n,m)。那么如果单独提出最后一列后,每一行的操作就是独立的了。
首先我们算出每一次操作真实询问的位置。这里的真实位置是指对于每一行加入维护出进入过该行的所有数以及次序,那么答案应该对应的是哪一个数。真实位置可以用之前的 BIT + 二分 解决。
如果真实位置
≤
m
−
1
\le m-1
≤m−1,那么可以直接求出,否则按询问输入顺序维护每一行从最后一列加入的数。
细节很多,具体可以看代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<queue>
#include<vector>
#define int long long
#define mp make_pair
using namespace std;
const int N=3e5+5;
int n,m,q,len;
int a[N],b[N],ans[N],bel[N],val[N*3];
vector<pair<int,int> > vec[N];
vector<int> ve[N];
inline int read()
{
int s=0,t=1;
char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')t=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=(s<<1)+(s<<3)+(ch^48),ch=getchar();
return s*t;
}
struct BIT
{
int len;
int c[N*3];
inline void init(){len=n+m+q;}
inline int lowbit(int i){return i&(-i);}
inline void add(int a,int b){for(int i=a+1;i<=len+1;i+=lowbit(i))c[i]+=b;}
inline void set(){for(int i=1;i<=len;++i)add(i,1);}
inline void reset(){for(int i=1;i<=len;++i)c[i]=0;}
inline int query(int a){int res=0;for(int i=a+1;i;i-=lowbit(i))res+=c[i];return res;}
}B;
inline bool check(int mid,int i){return B.query(mid)>=i;}
inline int calc(int i)
{
int l=1,r=B.len;
int pos=0;
while(l<=r)
{
int mid=(l+r)>>1;
if(check(mid,i))
{
pos=mid;
r=mid-1;
}
else l=mid+1;
}
return pos;
}
signed main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
n=read();
m=read();
q=read();
for(int i=1;i<=q;++i)
{
a[i]=read();
b[i]=read();
vec[a[i]].push_back(mp(b[i],i));
}
B.init();
B.set();
for(int x=1;x<=n;++x)
{
queue<int> tmp;
int sz=vec[x].size();
for(int i=0;i<sz;++i)
{
int y=vec[x][i].first;
int id=vec[x][i].second;
//printf("B.query(y):%d\n",B.query(y));
bel[id]=calc(y);
//printf("id:%lld bel:%lld\n",id,bel[id]);
if(bel[id]<m) ans[id]=(x-1)*m+bel[id];
B.add(bel[id],-1);
tmp.push(bel[id]);
}
while(!tmp.empty())
{
B.add(tmp.front(),1);
tmp.pop();
}
}
B.reset();
for(int i=1;i<=n;++i)
{
val[i]=i*m;
B.add(i,1);
}
len=n;
for(int i=1;i<=q;++i)
{
if(!ans[i])
{
int pos=bel[i]-m;
int num=0;
//printf("i:%lld pos:%lld sz:%lld\n",i,pos,(int)ve[a[i]].size()-1);
if(pos>(int)ve[a[i]].size()-1) num=calc(a[i]);
else num=ve[a[i]][pos];
ans[i]=val[num];
}
int pos=calc(a[i]);
B.add(pos,-1);
ve[a[i]].push_back(pos);
val[++len]=ans[i];
B.add(len,1);
//printf("DEL(%lld):%lld\n",a[i],val[len]);
}
for(int i=1;i<=q;++i) printf("%lld\n",ans[i]);
return 0;
}