UVA - 1513 Movie collection(树状数组)

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


猜你喜欢

转载自blog.csdn.net/lsd20164388/article/details/80698536