动态逆序对 BIT套线段树

本文深入探讨了动态逆序对算法的实现细节,通过使用线段树和差分数组等数据结构,有效地解决了动态更新场景下的逆序对计数问题。文章详细介绍了算法流程,包括初始化、查询和更新操作,适用于高级数据结构和算法的学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

动态逆序对

Code


#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define ll long long
using namespace std;
const int N=4e5;
const int M=3e7+100;
int root[M],sum[M],pos[N],lc[M],rc[M],A[M],B[M],b[N],a[N],c[N],tot=0,n,m,x;
ll ans=0;
int lowbit(int x){return x&-x;}
void add(int x,int v)
{while(x<=n)c[x]+=v,x+=lowbit(x);}
int ask(int x)
{int sum=0;while(x)sum+=c[x],x-=lowbit(x);return sum;}
void update(int &o,int L,int R,int x,int v){
    if(!o)o=++tot;
    int M=L+R>>1;
    sum[o]+=v;
    if(L==R)return;
    if(x<=M) update(lc[o],L,M,x,v);
    else update(rc[o],M+1,R,x,v);
}
int querymore(int l,int r,int L,int R,int v){
    int M=L+R>>1,tot=0;
    if(M+1>v){
        bool ok=0;
        for(int i=r;i;i-=lowbit(i))tot+=sum[rc[A[i]]];
        for(int i=l;i;i-=lowbit(i))tot-=sum[rc[B[i]]];
        for(int i=r;i;i-=lowbit(i))A[i]=lc[A[i]],ok|=A[i];
        for(int i=l;i;i-=lowbit(i))B[i]=lc[B[i]],ok|=B[i];
        
        if(ok) return querymore(l,r,L,M,v)+tot;
        return tot;
    }else{
        bool ok=0;
        for(int i=r;i;i-=lowbit(i))A[i]=rc[A[i]],ok|=A[i];
        for(int i=l;i;i-=lowbit(i))B[i]=rc[B[i]],ok|=B[i];
        if(ok) return querymore(l,r,M+1,R,v);
        return 0;
    }
}
int queryless(int l,int r,int L,int R,int v){
    int M=L+R>>1,tot=0;
    if(M<v){
        bool ok=0;
        for(int i=r;i;i-=lowbit(i))tot+=sum[lc[A[i]]];
        for(int i=l;i;i-=lowbit(i))tot-=sum[lc[B[i]]];
        for(int i=r;i;i-=lowbit(i))A[i]=rc[A[i]],ok|=A[i];
        for(int i=l;i;i-=lowbit(i))B[i]=rc[B[i]],ok|=B[i];
        if(ok) return queryless(l,r,M+1,R,v)+tot;
        return tot;
    }else{
        bool ok=0;
        for(int i=r;i;i-=lowbit(i))A[i]=lc[A[i]],ok|=A[i];
        for(int i=l;i;i-=lowbit(i))B[i]=lc[B[i]],ok|=B[i];
        if(ok) return queryless(l,r,L,M,v);
        return 0;
    }
}
void reset(int l,int r){
    for(int i=r;i;i-=lowbit(i))A[i]=root[i];
    for(int i=l;i;i-=lowbit(i))B[i]=root[i];
}
int main()
{
    //freopen("a.in","r",stdin);
    scanf("%d%d",&n,&m);
    rep(i,1,n){
        scanf("%d",&a[i]);
        pos[a[i]]=i;
    }
    rep(i,1,m) scanf("%d",&b[i]);
    rep(i,1,n){
        for(int x=i;x<=n;x+=lowbit(x))update(root[x],1,n,a[i],1);
        add(a[i],1); ans+=i-ask(a[i]);
    }
    rep(i,1,m){
        printf("%lld\n",ans);
        reset(0,pos[b[i]]-1);
        ans-=querymore(0,pos[b[i]]-1,1,n,b[i]);
        reset(pos[b[i]],n);
        ans-=queryless(pos[b[i]],n,1,n,b[i]);
        for(int x=pos[b[i]];x<=n;x+=lowbit(x))update(root[x],1,n,b[i],-1);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值