利用树状数组算最初的逆序对个数 nlogn
利用树状数组算出块中比x小的数的个数 logn
遍历x所在的那个块 n/S
总复杂度O( m(logn∗n/S+S)+nlogn )
S取 nlogn−−−−−√ 时 O( mnlogn−−−−−√+nlogn)
#include
#include
#include
using namespace std;
#define M 100005
#define N 80
int A[M],C[M],Cnt[N];
int n,m,S,G;
struct BIT{
int Sum[M];
void update(int x,int a){
while(x<=n)Sum[x]+=a,x+=x&(-x);
}
int query(int x){
int ans=0;
while(x)ans+=Sum[x],x-=x&(-x);
return ans;
}
}Bit[N];
long long Query(int x){
long long cnt=0;
int now=(C[x]-1)/S+1;
for(int i=1;ifor(int i=now+1;i<=G;i++)cnt+=Bit[i].query(x);
for(int i=(now-1)*S+1;i<=min(n,now*S);i++){
if(A[i]==0)continue;
if((A[i]>x&&iC[x]))cnt++;
}
return cnt;
}
void Update(int x){
A[C[x]]=0;
int now=(C[x]-1)/S+1;
Cnt[now]--;
Bit[now].update(x,-1);
}
int main(){
long long ans=0;
scanf("%d%d",&n,&m);
S=sqrt(n*log2(n));
G=(n-1)/S+1;
for(int i=1;i<=n;i++){
scanf("%d",&A[i]),C[A[i]]=i;
ans+=i-Bit[0].query(A[i])-1;
Bit[0].update(A[i],1);
}
for(int i=1;i<=G;i++)
for(int j=i*S-S+1;j<=min(i*S,n);j++)
Bit[i].update(A[j],1),Cnt[i]++;
for(int i=1;i<=m;i++){
int x;
scanf("%d",&x);
printf("%lld\n",ans);
Update(x);
ans-=Query(x);
}
return 0;
}
类似于分块
第一层的BIT就是代替分块的功能
但使用BIT的复杂度会比分块小很多 理解也难了很多
第一层的BIT对应的是下标,第二层的BIT是第一层所管辖到的子树
第二层负责维护信息,第一层负责映射出要查询的东西
可以说要更新一个值,先去找第一层
然后第一层再找第二层
可以说更新的永远是第二层
第一层只负责反馈和指挥第二层
代码实现:
#include
#include
#include
using namespace std;
#define M 100005
#define pb push_back
#define ll long long
int A[M],W[M];
int n,m;
struct NODE{
int Sum[M];
void insert(int x){
while(x<=n){
Sum[x]++;
x+=x&-x;
}
}
ll query(int x){
ll ans=0;
while(x){
ans+=Sum[x];
x-=x&-x;
}
return ans;
}
ll solve(){
ll ans=0;
for(int i=1;i<=n;i++){
ans+=i-query(A[i])-1;
insert(A[i]);
}
return ans;
}
}KG;
struct node{
vector<int>val;
vector<int>num;
int sz;
void init(){
sort(val.begin(),val.end());
sz=val.size()-1;
//erase(unique(val.begin(),vel.end()),val.end());
for(int i=1;i<=sz;i++){
num.pb(i&-i);
}
}
void update(int x){
int k=lower_bound(val.begin(),val.end(),x)-val.begin();//从该点开始更新
while(k<(int)val.size()){
num[k]--;
k+=k&-k;
}
sz--;
}
ll query(int x){
ll ans=0;
int k=lower_bound(val.begin(),val.end(),x)-val.begin()-1;//从该点前一点查询
while(k){
ans+=num[k];
k-=k&-k;
}
return ans;
}
}C[M];
ll Getsize(int x){
ll sum=0;
while(x){
sum+=C[x].sz;
x-=x&-x;
}
return sum;
}
ll Getsum(int x,int val){
ll sum=0;
while(x){
sum+=C[x].query(val);
x-=x&-x;
}
return sum;
}
void Init(){
for(int i=0;i<=n;i++)C[i].val.pb(0),C[i].num.pb(0);
for(int i=1;i<=n;i++){
int x=i;
while(x<=n){
C[x].val.pb(A[i]);
x+=x&-x;
}
}
}
void Del(int x,int val){
while(x<=n){
C[x].update(val);
x+=x&-x;
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&A[i]);
W[A[i]]=i;
}
Init();
for(int i=1;i<=n;i++)C[i].init();
long long tmp=KG.solve();
for(int i=1;i<=m;i++){
int x;
scanf("%d",&x);
printf("%lld\n",tmp);
ll sum1=Getsum(W[x]-1,x);
ll sum2=Getsize(W[x]-1);
ll sum3=Getsum(n,x);
tmp-=(sum2-sum1*2+sum3);
Del(W[x],x);
}
return 0;
}