树状数组+思想。其实看到这道题的第一眼感觉就是树状数组,然后就没有然后了。。。想了很久,才想到每用一张电影票的时候,我们就把这张票从原栈中删除,然后把这张电影票放在最前面(这句是废话。。当我没说。。),但是我们要怎么样放到前面呢?看看数据范围,我们发现可以把数组开成两倍的,然后就直接在原来数组范围的基础上(前面)放入这个这个数即可。
但是,这样的话我们要怎么记录票现在的位置的?这时我们就用到树状数组了。我们知道树状数组是一个修改区间求点的很好的一个工具。而且是log(n)的复杂的。用在这道题上就是妥妥的了。然后我们正常分析的话,是应该把一张票放到最前面的时候,本来在这张票之前的票的位置都是要+1的,这样的话,我们就知道,用树状数组去记录一个数被加了几次1,然后这道题差不多就解决了。注意:一个数位置变了之后,以前位置就作废了。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<fstream>
#include<sstream>
#include<cstdlib>
#include<vector>
#include<string>
#include<cstdio>
#include<bitset>
#include<queue>
#include<stack>
#include<cmath>
#include<map>
#include<set>
#define FF(i, a, b) for(int i=a; i<b; i++)
#define FD(i, a, b) for(int i=a; i>=b; i--)
#define REP(i, n) for(int i=0; i<n; i++)
#define CLR(a, b) memset(a, b, sizeof(a))
#define debug puts("**debug**")
#define LL long long
#define PB push_back
#define MP make_pair
using namespace std;
const int N = 202000;
int b[N], pos[N];
void add(int p, int a)
{
while(p < N)
{
b[p] += a;
p += p&(-p);
}
}
int sum(int p)
{
int ret = 0;
while(p)
{
ret += b[p];
p -= p&(-p);
}
return ret;
}
vector<int> pt;
const int ad = 100000;
int main()
{
int t, n, r, a;
scanf("%d", &t);
while(t --)
{
scanf("%d%d", &n, &r);pt.clear();
CLR(b, 0);
for(int i = 1; i <= n; i ++) pos[i] = i + ad;
for(int i = 0; i < r; i ++)
{
scanf("%d", &a);
pt.PB(pos[a] + sum(pos[a]));
add(1, 1);
add(pos[a], -1);
pos[a] = ad - i;
}
for(int i = 0; i < r; i ++) printf("%d ", pt[i] - ad - 1);puts("");
}
}