动态求逆序对--树状数组套线段树

     思路很容易想,麻烦的就是要实现一下动态开点线段树的修改操作,由于传统的主席树是依赖于前一个版本,所以如果想修改的话时间复杂度肯定会爆炸,于是我们想到了树状数组这个东西,把我们要修改的,线段树的个数降低到了log级别,而每次修改也是log,所以时间复杂度上是过的去的,怕卡常的话可以加个快读快写,然后注意开一下Long long。

     所谓树状数组套线段树,就是把朴素版的树状数组里的一个个元素换成一颗颗独立的线段树,大体的操作没有变,就是在修改值的时候用到了动态开点线段树的修改。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#define int long long
using namespace std;
const int N=1e5+10;
int n,idx,q;
int root[N*16*6];
struct xdss
{
    int lson,rson,cnt;
}xds[N*16*6];
void motify(int &rt,int l,int r,int pos,int val)
{
    if(!rt) rt=++idx;
    xds[rt].cnt+=val;
    if(l==r) return;
    int mid=l+r>>1;
    if(pos<=mid) motify(xds[rt].lson,l,mid,pos,val);
    else motify(xds[rt].rson,mid+1,r,pos,val);
}
int query(int rt,int l,int r,int ll,int rr)
{
    if(rt==0) return 0;
    if(ll<=l&&r<=rr) return xds[rt].cnt;
    int mid=l+r>>1;
    int res=0;
    if(ll<=mid) res=query(xds[rt].lson,l,mid,ll,rr);
    if(rr>mid) res+=query(xds[rt].rson,mid+1,r,ll,rr);
    return res;
}
int lowbit(int x){return x&-x;}
void szmotify(int id,int x,int val){for(int i=id;i<=n;i+=lowbit(i)) motify(root[i],1,n,x,val);}
int szquery(int id,int x,int type)
{
    int res=0;
    if(type==1)
    {
        //   cout<<res<<'\n';
        for(int i=id;i;i-=lowbit(i))
        {
            //    cout<<res<<'\n';
            res+=query(root[i],1,n,x+1,n);
        }
    }
    if(type==2)
    {
        for(int i=n;i;i-=lowbit(i)) res+=query(root[i],1,n,1,x-1);
        for(int i=id-1;i;i-=lowbit(i)) res-= query(root[i],1,n,1,x-1);
    }
    return res;
}
void solve()
{
    cin>>n>>q;
    int res=0;
    map<int,int>s;
    for(int i=1;i<=n;i++)
    {
        int x;
        cin>>x;
        s[x]=i;
        res+=szquery(s[x]-1,x,1);
        szmotify(i,x,1);
    }
    while(q--)
    {
        cout<<res<<"\n";
        int x;
        cin>>x;
        int a=0,b=0;
        if(x<n) a+= szquery(s[x]-1,x,1);//前面大于x的个数
        if(x>1) b+= szquery(s[x]+1,x,2);//小于x的个数
        res-=(a+b);
        szmotify(s[x],x,-1);
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
    int T=1;
    while(T--){solve();}
    return 0;
}

  • 10
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值