题意:给你一摞共n(n<=1e5)个光盘,刚开始从下到上依次是光盘n,n-1,n-2,...,1号。现在出题人要看m(m<=1e5)次光盘,每一次都会抽出光盘a[i]号并放到最上面。让你求每一次抽出光盘a[i]时,抽出的光盘上方有几个光盘。
思路:树状数组。容易想到抽出一个光盘,然后对于在其上面的每一个光盘,在它上面的光盘数都会增加1,因此只需要记录一下每个光盘的位置,然后树状数组开大一点,每次把抽出的光盘放到树状数组下界的位置。位于树状数组下界位置的下标+1到抽出的光盘原先的位置全部+1即可。
注意初始化。
代码:
#include <bits/stdc++.h>
#define ll long long
#define lson i*2,l,m
#define rson i*2+1,m+1,r
using namespace std;
const int maxn=200100;
const int mo=1e9+7;
using namespace std;
int a[maxn],c[maxn],d[maxn];
int tmp;
int n,m;
int lowbit(int i){return i&-i;}
int query(int i,int st)
{
int sum=0;
while(i>st){
sum+=a[i];
i-=lowbit(i);
}
return sum;
}
void add(int i,int x){
while(i<maxn){
a[i]+=x;
i+=lowbit(i);
}
}
int main()
{
tmp=100005;
int T,cas=1;
for(int i=1;i<tmp;i++)
{c[i]=tmp+i;
if(i>1) add(tmp+i,1);
}
for(int i=0;i<maxn;i++)
d[i]=a[i];
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&m);
tmp=100005;
for(int i=1;i<=n;i++)
{c[i]=tmp+i;}
for(int i=0;i<maxn;i++)
a[i]=d[i];
bool flag=0;
while(m--){
int j;
scanf("%d",&j);
int k=query(c[j],tmp);
add(tmp+1,1);
add(c[j],-1);
c[j]=tmp;
tmp--;
if(flag) printf(" %d",k);
else {printf("%d",k);flag=1;}
}
puts("");
}
return 0;
}