题意:给你一摞共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; }