用线段树去模拟,开始每点的值为1,单点查询相对位置,然后用vis数组记录结果,将该点的值置0。
比如,我查第一个删除的点的相对位置为1,然后线段树找了了val[i]=1的位置,然后将该点置为0,删除下一个点的时候,相对位置就是k+1-1(因为前面已经删了一个了),然后用线段树找,再下一个点的时候相对位置就是k*2+1-2;
然后如果相对位置temp小于等于左边的val,就往左走,否则就往右走,temp=temp-val[i<<1];
时间复杂度为 : O(nlogn)
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 3000000+10;
int vis[maxn];
int val[maxn<<2];
void build(int i,int l,int r)
{
val[i]=0;
if(l==r)
{
val[i]=1;
vis[l]=0;
return ;
}
int mid=(l+r)>>1;
build(i<<1,l,mid);
build(i<<1|1,mid+1,r);
val[i]=val[i<<1]+val[i<<1|1];
}
int h=1;
void sert(int i,int l,int r,int temp)
{
if(l==r)
{
vis[h++]=l;
val[i]=0;
return ;
}
int mid=(l+r)>>1;
if(temp<=val[i<<1]) sert(i<<1,l,mid,temp);
else {
sert(i<<1|1,mid+1,r,temp-val[i<<1]);
}
val[i]=val[i<<1]+val[i<<1|1];
}
int main()
{
// freopen("E:\\input.txt","r",stdin);
int T;
scanf("%d",&T);
while(T--)
{
memset(vis,0,sizeof(vis));
memset(val,0,sizeof(val));
int n,k,q;
scanf("%d %d %d",&n,&k,&q);
build(1,1,n);
int i=0,t=0,num=n;
h=1;
while(num)
{
int temp=k*i+1-t;
if(temp<=num)
{
sert(1,1,n,temp);
i++;
t++;
num--;
}
else {
i=0;
t=0;
}
}
while(q--)
{
int a;
scanf("%d",&a);
printf("%d\n",vis[a]);
}
}
return 0;
}