题目
有一个n*m的方阵,一开始,格子(i,j)上的数是(i-1)*m+j
有q次操作,每次给定
(
x
,
y
)
(x,y)
(x,y),将格子(x,y)中的数取出,第x行的数向左补空,然后第m列的数向前补空。
50分,q<=500,n,m<=50000
另30分,x=1
100分,n,m,q<=300000
题解
部分分?
50分:用vector。
由于q<=500,所以涉及到换位置的数不超过500*50000个。
时间复杂度:
O
(
q
n
∗
l
o
g
n
)
O(qn*log\ n)
O(qn∗log n)
开50000个vector。
v[i]表示第i行的数。
显然,将(x,y)取出后,(x,y)左边的数是不会动的。
所以,如果对于第x行,y是这么多次操作中最小的,那么将没有动过的那些数也加入vector。
做完这步之后,就只剩下交换操作了。
80分:x=1
直接线段树。维护sum和标记。
不要开小数组!!
100分:结合2种做法:
开300001(n+1)个线段树,每个线段树维护着一些连续的区间。
显然,每个线段树开始只有1个点。
进行一次操作。如果y<m,那么有2个线段树将分裂区间。
否则,代表最后一列的那棵线段树将分裂区间。
同样地,要维护标记。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define N 300010
#define LL long long
#define P(a) putchar(a)
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct note{
int sum,ls,rs;
LL bj;
};note tr[N*40];
int i,j,k,l;
LL n,m,q,q1,wz;
int u,v;
int tot;
int root[N],tail[N];
LL ans,temp;
int read(){
int res=0,fh=1;char ch;
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar();
return res*fh;
}
void write(LL x){
if(x>9)write(x/10);
P(x%10+'0');
}
void update(int ps){
tr[ps].sum=tr[tr[ps].ls].sum+tr[tr[ps].rs].sum;
}
LL find(int &ps,int l,int r,LL x){
if(!ps)ps=++tot;
if(l==r){
wz=l;
tr[ps].sum=1;
return tr[ps].bj;
}
int mid=(l+r)>>1;
LL res;
if(x>mid-l+1-tr[tr[ps].ls].sum)
res=find(tr[ps].rs,mid+1,r,x-(mid-l+1-tr[tr[ps].ls].sum));
else res=find(tr[ps].ls,l,mid,x);
update(ps);
return res;
}
void change(int &ps,int l,int r,int x,LL z){
if(!ps)ps=++tot;
if(l==r){
tr[ps].bj=z;
return;
}
int mid=(l+r)>>1;
if(x<=mid)change(tr[ps].ls,l,mid,x,z);
else change(tr[ps].rs,mid+1,r,x,z);
update(ps);
}
int main(){
cin>>n>>m>>q;
tail[n+1]=n;
fo(i,1,n)tail[i]=m-1;
q1=q;
while(q1--){
ans=0;
u=read(),v=read();
if(v==m){
wz=0;
ans=find(root[n+1],1,n+q,u);
if(wz<=n)ans=1ll*wz*m;
change(root[n+1],1,n+q,++tail[n+1],ans);
} else{
wz=0;
temp=find(root[u],1,m+q,v);
if(wz<=m-1)ans=1ll*(u-1)*m+1ll*wz;else ans=temp;
change(root[n+1],1,n+q,++tail[n+1],ans);
wz=0;
temp=find(root[n+1],1,n+q,u);
if(wz<=n)temp=1ll*wz*m;
change(root[u],1,m+q,++tail[u],temp);
}
write(ans),P('\n');
}
return 0;
}