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;
}