题目描述
题解
观察到每一个点离队以后方阵的变化,可以发现:
- 对于每一个离队,如果是最后一列,变化的仅仅只有最后一列。
- 如果离队的不是最后一列,则变化的是这一行以及最后一列。
因此,我们需要动态维护 n n n行列为 [ 1 , m − 1 ] [1,m-1] [1,m−1]的方阵队形,并且维护最后一列的方阵队形。
我们所进行的操作就是,在删除节点的位置标记一个 1 1 1 ,在其余位置标记一个 0 0 0 ;那么只需要找到 p p p 和 0 0 0 就说明找到了第 p p p 个人.这显然可以用线段数进行维护。由于需要建立 n n n 个线段树,所以需要使用动态开店线段数来进行维护。具体如何维护这里就不多说了。
大体的思路知道了,我们来考虑一下如何求解最终需要的答案。
如果我们求解的是最后一列的答案,可以进行这样的操作:
- 如果当前位置 p o s ≤ n pos\leq n pos≤n ,可以直接输出 m ∗ p o s m*pos m∗pos. 将这个点边权加上 1 1 1 ,标记未删除。再将这个点添加到一个 v e c t o r vector vector 内,表示这一列后面新加入的节点。
- 直接输出 v e c t o r vector vector内下标为 n − p o s − 1 n-pos-1 n−pos−1 的数值,进行和上面相同的操作。
如果不是最后一列的答案,处理就变得十分麻烦了:
- 首先需要找到这一个序列中位置为 y y y 的编号,输出这个编号 t t t 。考虑新加入序列的编号是多少。
- 在最后一列找到位置为 x x x 的编号,加入原来维护的第 x x x 行中,再将这个数删除加入新数 t t t 。
代码如下:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 5e5;
const int Max = 1e6;
int n, m, q, cnt = 0;
int root[N];
vector <int> New[N];
struct SegmentTree {
int sum, lc, rc;
} a[N*10];
void change(int &p,int l,int r,int x)
{
if (p == 0) p = ++cnt;
if (l == r) { a[p].sum ++; return; }
int mid = l+r >> 1;
if (x <= mid) change(a[p].lc,l,mid,x);
if (x > mid) change(a[p].rc,mid+1,r,x);
a[p].sum = a[a[p].lc].sum+a[a[p].rc].sum;
return;
}
int ask(int p,int l,int r,int k)
{
int mid = l+r >> 1;
if (l == r) return r;
int sum = (mid-l+1)-a[a[p].lc].sum;//a数组内的sum表示删除的个数
//sum表示左边还剩下几个数
if (sum >= k)
return ask(a[p].lc,l,mid,k);
else return ask(a[p].rc,mid+1,r,k-sum);
}
int query2(int x,int num)
{
int pos = ask(root[0],1,Max,x), ans;
change(root[0],1,Max,pos);
if (pos <= n) ans = m*pos;
else ans = New[0][pos-n-1];//ans表示最后一列第x行的编号
if (num == 0) New[0].push_back(ans);//第x行的转移到了最有一行
else New[0].push_back(num);//中间的跳到最有一行
//del记录线段数中那些多出来的节点
return ans;
}
int query1(int x,int y)
{
int pos = ask(root[x],1,Max,y), ans;
change(root[x],1,Max,pos);
if (pos < m) ans = (x-1)*m+pos;//原来存在
else ans = New[x][pos-m];//新增加
New[x].push_back(query2(x,ans));
return ans;
}
signed main(void)
{
scanf("%lld %lld %lld", &n, &m, &q);
for (int i=0;i<=n;++i) root[i] = ++cnt;
while (q --)
{
int x, y;
scanf("%lld %lld", &x, &y);
if (y == m) printf("%lld\n", query2(x,0));
else printf("%lld\n", query1(x,y));
}
return 0;
}