#include <cstdio>
#include <iostream>
#include <cstring>
#include <map>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <set>
#include <queue>
#include <vector>
#include <stack>
using namespace std;
const int maxn = 1e5 + 5;
int c[2 * maxn];//树状数组
int pos[maxn];//原始数组
int n, m;
int lowbit(int x)//求某个点的管辖范围
{
return (x&(-x));//加上求得管辖x的点,减去求得x管辖的点
}
void add (int p, int v)//修改树状数组
{
while (p < 2 * maxn)
{
c[p] += v;//p加一,所有管辖p的点都要加一
p += lowbit(p);//这句不断找到所有管辖p的点
}
}
int sum (int p)//sum(x)就是求前x项的和
{
int ret = 0;//求和
while (p > 0)
{
ret += c[p];
p -= lowbit(p);//求得x管辖的点
}
return ret;
}
int main ()
{
int T;
scanf ("%d", &T);
while (T--)
{
memset (c, 0, sizeof (c));
scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
pos[i] = n - i + 1;//因为建树要从根节点开始,树的位置和原始位置是反着的,比如n=16时,i=16,它在树状数组是根,所以位置是1。
add(pos[i], 1);//依据原始数组构建树状数组
}
int num;
int N = n;
for (int i = 1; i <= m; i++)
{
scanf ("%d", &num);
printf ("%d%c", n - sum(pos[num]), i == m ? '\n':' ');
//举例说下位置问题:还是假设n=16,num=7时按照题意应该求7上面有多少部电影,用sum求的是树状数组1-10的和,相当于
//原始数组的7-16的和,所以在用n减去就是目标值,和上面的位置储存正好对应
add(pos[num], -1);//修改树状数组,拿出这部电影
pos[num] = ++N;//num处理完后位置改变,N最大为2*n,所以c这个树状数组要开2*maxn
add(pos[num], 1);//修改树状数组,添加树的叶,把这部电影放到最上面
}
}
return 0;
}
初学者结合着这个博客看看很快就能理解树状数组了
http://www.cnblogs.com/Penn000/articles/5758324.html