列队

· · 个人记录

#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long
using namespace std;
const int N = 3e5+5,M =1e7; 
LL n,m,p,R,now;//R最长(差)M
LL rt[N],len[M],ls[M],rs[M],tot,le[N];
LL num[M];
inline void read(LL &x){
    char ch=getchar();x=0;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
}
inline void point(LL x){
    if(x>9)point(x/10);
    putchar(x%10+'0');
}
inline LL get(LL l,LL r){
    if(now==n+1){
        if(r<=n)return r-l+1;
        if(l<=n)return n-l+1;
        return 0;
    }
    if(r<m)return r-l+1;
    if(l<m)return m-l;
    return 0;
}
inline void add(LL &k,LL p,LL w,LL l,LL r){
    if(!k){
        k=++tot;
        len[k]=get(l,r);//这一段没人离开过,是完整的,趁这时记录下实际长度 ,方便查找 (用x(题目给出)寻人)与cut (剪出),总之与add无关 
        if(l==r)num[k]=w;
    }
    len[k]++;
    if(l==r)return;
    LL mid=(l+r)>>1;
    if(p<=mid)add(ls[k],p,w,l,mid);
    else add(rs[k],p,w,mid+1,r);
}
inline LL cut(LL &k,LL p,LL l,LL r){
    if(!k){
        k=++tot;
        len[k]=get(l,r);
        if(l==r){
            if(now==n+1)num[k]=m*l;
            else num[k]=(now-1)*m+l;//人编号 
        }
    }
    len[k]--;// 相当于有一个人走了,位子虽然还在,但后面cut运算都忽略不记,
    //(再次强调add操作与实际len,cnt等等无关,就是线段树单点修改)  
    if(l==r)return num[k];//剪走 
    int mid=l+r>>1;//是len表示mid 在(1-》R)中的实际位置 
    //(r-l)/2+1   因为l!=0,r!=n开始 是[已开发的]伪区间 
    if(!ls[k]&&p<=mid-l+1||p<=len[ls[k]])return cut(ls[k],p,l,mid);//《1》r=l+1时,mid-l=0!故mid-l+1 ,《2》与p比较用mid转化为实际队列中的下标x 
    else{
        if(!ls[k])p-=mid-l+1;
        else p-=len[ls[k]];
        return cut(rs[k],p,mid+1,r);
    }
}
int main(){
    read(n),read(m),read(p);
    R=max(n,m)+p;
    LL x,y,ans;
    while(p--){
        read(x),read(y);
        if(y==m){
            now=n+1;ans=cut(rt[now],x,1,R);
        }else now=x,ans=cut(rt[now],y,1,R);
        point(ans);
        putchar('\n');
        now=n+1;add(rt[now],n+(++le[now]),ans,1,R);//(有le数组记录多出长度,直接用p(结构下标)加人) 
        if(y!=m){
            now=n+1,ans=cut(rt[now],x,1,R);
            now=x;add(rt[x],m-1+(++le[now]),ans,1,R);//由题,无论是  1-》n(行) 还是 n+1(最后一列) 只会在末尾加人 
        }   
    }
    return 0;
}
/*
2 2 3
1 1
2 2
1 2
*/