UVALive5902:Movie collection

UVALive5902:Movie collection


题目大意


给定n个数字,有m次查询,每次查询数字i的前面有几个数字,然后将数字i放到所有数字之前。最开始的时候,所有数字按照1,2,3...n这样的升序排列

要求复杂度:Ο(nlogn)

Solution


在一个数组中,每个数字所处的位置标记为1,没有数字的标记为0。这样每次查询就是查询某个数字所在位置的前缀和。

用一个数组id维护每个数字当前在C数组中所处的位置,也即是id[i]是数字i在C数组中的下标,用树状数组处理C数组。

最开始的时候,把数字存在m+1~m+n这个范围内,因为最多有m次查询,每次查询的时候把一个数字放到队列的前端,可以用一个变量cur维护当前队列最前端的下标。cur初始化为m

AC-Code(C++)


Time:146ms

#include <iostream>
#include <iomanip>
#include <algorithm>
#include <string>
#include <cstring>
#include <map>
#include <set>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <climits>
#include <ctime>
#include <cctype>

using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1.0);
const int maxn = 200000 + 10;
/**
 * 刘汝佳 训练指南P246
 */

int T,n,m;
int C[maxn];
int id[maxn];

int lowbit(int x){
    return x&-x;
}

int getSum(int x){
    int ret = 0;
    while(x > 0){
        ret += C[x];
        x -= lowbit(x);
    }
    return ret;
}

void change(int x,int from,int to){
    while(x <= m+n){
        C[x] -= from;
        C[x] += to;
        x += lowbit(x);
    }
}

int main(int argc, const char * argv[]) {
    
//    freopen("input.txt", "r", stdin);

    scanf("%d",&T);
    while(T--){
        memset(C, 0, sizeof(C));
        scanf("%d %d",&n,&m);
        int cur = m;
        for(int i=1;i<=n;i++){
            id[i] = m + i;
            change(m+i, 0, 1);
        }
        for(int i=0;i<m;i++){
            int movie;
            scanf("%d",&movie);
            if(i)
                printf(" %d",getSum(id[movie]-1));
            else
                printf("%d",getSum(id[movie]-1));
            change(id[movie], 1, 0);
            id[movie] = cur--;
            change(id[movie], 0, 1);
        }
        printf("
");
    }

    return 0;
}
原文地址:https://www.cnblogs.com/irran/p/8859566.html