洛谷 P3157 动态逆序对(归并排序+树状数组套主席树)

先归并排序处理出初始逆序对数

然后树状数组套主席树进行修改和查询

删除数x时(设x位置为pos[x]),从原逆序对数中减去与该数有关的逆序对数,即([1,pos[x]-1]中大于x的数的个数)+([pos[x]+1,n]中小于x的数的个数),并从树状数组中将x删除

另外注意存答案要用long long,否则会爆

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int maxn=100010;
    typedef long long LL;
    int n,m,a[maxn],pos[maxn];
    LL ans;
    inline int read(){
        int ret=0,sign=1;
        char ch=getchar();
        while(ch<'0'||ch>'9') {if(ch=='-') sign=-1; ch=getchar();}
        while(ch>='0'&&ch<='9') {ret=ret*10+ch-'0'; ch=getchar();}
        return ret*sign;
    }
    struct node{
        int sum,son[2];
    }T[maxn*300];
    int root[maxn],cnt;
    int tmp1[maxn],tmp2[maxn];
    LL merge(int l,int r){
        if(l==r) return 0;
        int mid=(l+r)>>1;
        LL ret=merge(l,mid)+merge(mid+1,r);
        int i=l,j=mid+1,k=l;
        for(;j<=r;j++){
            while(i<=mid&&tmp1[i]<=tmp1[j]) tmp2[k++]=tmp1[i++];
            ret+=mid-i+1,tmp2[k++]=tmp1[j];
        }
        for(;i<=mid;i++)
            tmp2[k++]=tmp1[i];
        for(int p=l;p<=r;p++)
            tmp1[p]=tmp2[p];
        return ret;
    }
    void ins(int &u,int l,int r,int x,int op){
        if(!u) u=++cnt;
        T[u].sum+=op;
        int mid=(l+r)>>1;
        if(l==r) return;
        if(x<=mid) ins(T[u].son[0],l,mid,x,op);
        else ins(T[u].son[1],mid+1,r,x,op);
    }
    inline int lbt(int x){return x&(-x);}
    inline void add(int u,int op){for(int i=u;i<=n;i+=lbt(i)) ins(root[i],1,n,a[u],op);}
    int tmpU[2][20],tmpN[2];
    LL query(int l,int r,int x,int op){
        if(l>r) return 0;
        tmpN[0]=tmpN[1]=0;
        for(int i=l-1;i;i-=lbt(i)) tmpU[0][++tmpN[0]]=root[i];
        for(int i=r;i;i-=lbt(i)) tmpU[1][++tmpN[1]]=root[i];
        int vl=1,vr=n;
        LL ret=0;
        if(op==1) while(1){
            if(vr==x) break;
            int mid=(vl+vr)>>1,rsum=0;
            for(int i=1;i<=tmpN[0];i++) rsum-=T[T[tmpU[0][i]].son[1]].sum;
            for(int i=1;i<=tmpN[1];i++) rsum+=T[T[tmpU[1][i]].son[1]].sum;
            int rela=x>mid;
            if(!rela) ret+=rsum,vr=mid;
            else vl=mid+1;
            for(int i=1;i<=tmpN[0];i++) tmpU[0][i]=T[tmpU[0][i]].son[rela];
            for(int i=1;i<=tmpN[1];i++) tmpU[1][i]=T[tmpU[1][i]].son[rela];
        }
        else while(1){
            if(vl==x) break;
            int mid=(vl+vr)>>1,lsum=0;
            for(int i=1;i<=tmpN[0];i++) lsum-=T[T[tmpU[0][i]].son[0]].sum;
            for(int i=1;i<=tmpN[1];i++) lsum+=T[T[tmpU[1][i]].son[0]].sum;
            int rela=x>mid;
            if(rela) ret+=lsum,vl=mid+1;
            else vr=mid;
            for(int i=1;i<=tmpN[0];i++) tmpU[0][i]=T[tmpU[0][i]].son[rela];
            for(int i=1;i<=tmpN[1];i++) tmpU[1][i]=T[tmpU[1][i]].son[rela];
        }
        return ret;
    }
    int main(){
        n=read(),m=read();
        for(int i=1;i<=n;i++)
            tmp1[i]=a[i]=read(),pos[a[i]]=i;
        ans=merge(1,n);
        for(int i=1;i<=n;i++)
            add(i,1);
        for(int i=1;i<=m;i++){
            int x=read();
            printf("%lld\n",ans);
            ans-=query(1,pos[x]-1,x,1)+query(pos[x]+1,n,x,-1);
            add(pos[x],-1);
        }
        return 0;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值