题面在这里
突然来填这个noip坑。顺便记一下一个可怕的错误。
做法
动态开点线段树+二分即可。
主要思想就是将题意转化为删除+插入操作,删除打1的标记。
代码
=> 用 while (q--)
的时候一定要留心看下下面有没有用到q =_=
#include<bits/stdc++.h>
#define rep(i,x,y) for (int i=(x); i<=(y); i++)
#define ll long long
#define ld long double
#define inf 1000000000
using namespace std;
ll read(){
char ch=getchar(); ll x=0; int op=1;
for (; !isdigit(ch); ch=getchar()) if (ch=='-') op=-1;
for (; isdigit(ch); ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
return x*op;
}
#define N 300005
#define M 8000005
int siz[M],pos[N],ls[M],rs[M],rt[N],tot,loc; ll n,m,q,val[M];
ll getkth(int &k,int l,int r,int now,int &loc){
if (!k) k=++tot;
if (l==r){ siz[k]=1; loc=l; return val[k]; }
int mid=l+r>>1; ll ret;
if (mid-l+1-siz[ls[k]]>=now) ret=getkth(ls[k],l,mid,now,loc);
else ret=getkth(rs[k],mid+1,r,now-(mid-l+1-siz[ls[k]]),loc);
siz[k]=siz[ls[k]]+siz[rs[k]]; return ret;
}
void ins(int &k,int l,int r,int x,ll y){
if (!k) k=++tot;
if (l==r){ val[k]=y; return; }
int mid=l+r>>1;
if (x<=mid) ins(ls[k],l,mid,x,y); else ins(rs[k],mid+1,r,x,y);
siz[k]=siz[ls[k]]+siz[rs[k]];
}
int main(){
n=read(),m=read(),q=read();
rep (i,1,n) pos[i]=m-1; pos[n+1]=n;
rep (i,1,q){//傻子如我写成了while (q--)。
int x=read(),y=read();//1表示删除。
if (y==m){//第y个未删除的位置
ll tmp=getkth(rt[n+1],1,n+q,x,loc);
if (loc<=n) tmp=loc*m;
printf("%lld\n",tmp);
ins(rt[n+1],1,n+q,++pos[n+1],tmp);
} else{
ll tmp=getkth(rt[x],1,m+q,y,loc);
if (loc<m) tmp=(x-1)*m+loc;
printf("%lld\n",tmp);
ins(rt[n+1],1,n+q,++pos[n+1],tmp);
tmp=getkth(rt[n+1],1,n+q,x,loc);
if (loc<=n) tmp=loc*m;
ins(rt[x],1,m+q,++pos[x],tmp);
}
}
return 0;
}