每行用一个线段树来维护在这行的人的信息,最后一列用一个线段树在这行的人的信息。
一个人离队。
如果这个人(代号人1)不在最后一列,出队,就把他的信息从他所在的行所代表的线段树中删除,再把在这一行最后一列的人(代号人2)的信息从最后一列删除,再把人2的信息加入到这一行的的线段树中。最后把人1的信息加入到最后一列所在的线段树的末尾。
如果这个人在最后一列,把他他的信息从线段树里删除,再加到最后一列所在的线段树的末尾
然而显然爆空间,所以考虑动态开节点。//要要到这个点的信息时才开。
线段树上每个节点维护这个点所代表的区间有多少个人-。-
叶子节点还要维护在站在这个点的人的编号。
每棵线段树的大小为:
每行的线段树:m+q
最后一列的线段树n+q;
//pos表示的含义,query中pos是它在这一行或列中是第几个,modify中pos为它加的位置的下标。
query,modify如果访问到没访问的节点,则新开一个节点,处理出这个区间有多少个人(如果第一次肯定没有删除过所以可以用节点所代表的l,r来处理出),如果是叶子节点还要处理编号(用一个hs代表这个人是在行所代表的线段树还是在列所代表的线段树)。
我的query顺便带了删除,其实写到modify里也可以,但是这样写可以降低复杂度.
#include<iostream>
#include<cstdio>
using namespace std;
int n, m, q, tp, end[6000004], rt[6000004], ls[6000004], rs[6000004];
long long tot,siz[6000004], val[6000004];
void read(int &x)
{
x = 0;char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9')
{
x = 10 * x + c - '0';
c = getchar();
}
}
int suan(int l,int r,int hs)
{
if(hs == n + 1)
{
if(r <= n)
{
return r - l +1;
}
else if(l <= n) return n - l +1;
else return 0;
}
else
{
if(r <= m-1)
{
return r - l +1;
}
else if(l <= m-1) return m - l;
else return 0;
}
}
long long qurey(int &o,int l,int r,int pos,int hs)
{
if(o == 0)
{
o = ++tot;
siz[o] = suan(l,r,hs);
if( l == r)
{
if(hs == n+1)val[o] = 1ll * m * l;
else val[o] = 1ll * m * (hs-1) + 1ll * l;
}
}
siz[o]--;
if(l == r) return val[o];
int mid = (l + r) / 2;
if(siz[ls[o]] >= pos || (ls[o] == 0 && (mid-l+1) >= pos)) return qurey(ls[o],l, mid, pos,hs);
else
{
if(ls[o]) pos -= siz[ls[o]]; else pos -= (mid - l +1);
return qurey(rs[o],mid+1, r,pos,hs);
}
}
void modify(int &o,int l,int r,int pos, long long va,int hs)
{
if(o == 0)
{
o = ++ tot;
siz[o] = suan(l,r,hs);
if( l == r) val[o] = va;
}
siz[o]++;
if(l == r) return ;
int mid = (l + r) /2;
if(mid >= pos) modify(ls[o],l,mid,pos,va,hs);
else modify(rs[o],mid+1,r,pos,va,hs);
}
int main()
{
//freopen("ha.in","r",stdin);
//freopen("ha.out","w",stdout);
read(n); read(m); read(q);
for(int i = 1; i <= n; i++)
{
rt[i] = ++tot; end[i] = m - 1;
}
rt[n+1] = ++tot; end[n + 1] = n;
for(int i = 1; i <= q; i++)
{
long long x,y; scanf("%lld",&x);
scanf("%lld",&y);
if(y == m)
{
long long ha = qurey(rt[n+1],1,n+q,x,n+1);
end[n+1]++;
printf("%lld\n",ha);
modify(rt[n+1],1,n+q,end[n+1],ha,n+1);
continue;
}
long long ha = qurey(rt[n+1], 1, n+q, x, n+1);
long long he = qurey(rt[x], 1, m-1+q, y, x);
printf("%lld\n",he);
end[x]++; end[n+1]++;
modify(rt[x], 1, m-1+q, end[x], ha, x);
modify(rt[n+1], 1, n+q, end[n+1],he,1 + n);
}
return 0;
}