理解树状数组的模板:就三部分组成:lowbit函数,区间求和函数( sum() ),单点更新函数( add() ),这表明了每改变区间中的某个点就必须调用一下add函数,因为一个点的改变会造成所有c数组里面其它元素的改变。那么什么是c数组呢?
这个就是虚拟的一个数组,不知道为什么的可以去网上搜一下lowbit函数的原理,因为我们就是靠它来构造c数组。
接着关于区间求和,我们是直接用sum(x)-sum(y)来得到[x,y]这一段区间的和。
好了,树状数组模板介绍完毕,接下来是关于这道题目:
思路:此题让我们求的是连续的一些数1,2,3……n,对于每个数求在其前面有几个数,并输出,接着把该数放到第一位去,其它数字相应后移。这题的思路可以这样:
初始的时候,题目告诉我们有一串数是1234……n,我们将它反过来看:n,n-1,n-2……3,2,1,反过来以后其对应位置(pos)为:1,2,3,4……n
for example:
假设n=6,m=3,令a数组为:11111100000………………(把a数组开大一点,预留至少n+m个空位),每一位代表了6,5,4,3,2,1...
令pos[6]=1,pos[5]=2,pos[4]=3,pos[3]=4,pos[2]=5,pos[1]=6;
求和可得到:sum[pos[1]]=6,sum[pos[2]]=5,sum[pos[3]]=4……sum[pos[n]]=1;
假设查询为6 4 2,则第一次输出sum[pos[n+m]]-sum[pos[6]]=6-1=5;然后我们调用add函数进行单点修改(只有用了树状数组的单点修改才能用它的区间求和):
add(pos[6],-1); ------------------------------------------------------------------------------ 这一步表示原来位置上的6被移走,原位置减1变成0
int len=n+1,pos[6]=len++;-----------------------------------------------------------------这一步表示6被移到新位置
add(pos[6],1);---------------------------------------------------------------------------------这一步表示新位置加1
第二次操作:输出sum[pos[n+m]]-sum[pos[4]]=6-2=4;然后我们调用add函数进行单点修改:
add(pos[4],-1); ------------------------------------------------------------------------------ 这一步表示原来位置上的4被移走,原位置减1变成0
pos[4]=len++;-----------------------------------------------------------------这一步表示4被移到新位置
add(pos[4],1);---------------------------------------------------------------------------------这一步表示新位置加1
第三次操作:输出sum[pos[n+m]]-sum[pos[2]]=6-2=4;然后我们调用add函数进行单点修改:
add(pos[2],-1); ------------------------------------------------------------------------------ 这一步表示原来位置上的4被移走,原位置减1变成0
pos[2]=len++;-----------------------------------------------------------------这一步表示4被移到新位置
add(pos[2],1);---------------------------------------------------------------------------------这一步表示新位置加1
输出的是5 4 4
代码:
#include<cstdio>
#include<cstring>
#include<string>
#include<string.h>
#include<queue>
#include<algorithm>
#include<iostream>
#include<math.h>
#define maxn 300008
#define ll long long
#define RPG(i,a,b) for(int i=(a);i<(b);i++)
using namespace std;
int n,a[maxn],c[maxn];
int lowbit(int x)
{
return (x&(-x));
}
int sum(int x)
{
int ret=0;
while(x>0)
{
ret+=c[x];
x-=lowbit(x);
}
return ret;
}
int add(int x,int d)
{
while(x<=n)
{
c[x]+=d;
x+=lowbit(x);
}
}
const int N = 3e5+7;
int len;
int pos[N];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
memset( c, 0, sizeof(c) );
int m;
scanf("%d%d",&n,&m);
len = n+1;
n += m;
RPG(i,1,len)
{
add(i,1);
pos[i] = len-i;
}
int f=1;
RPG(i,0,m)
{
int x;
scanf("%d",&x);
if(f)
{
f=0;
printf("%d",sum(n)-sum(pos[x]));
}
else
printf(" %d",sum(n)-sum(pos[x]));
add( pos[x], -1 );
pos[x] = len++;
add( pos[x], 1 );
}
puts("");
}
return 0;
}