zoukankan      html  css  js  c++  java
  • [BZOJ 3295] 动态逆序对

    Link:

    BZOJ 3295 传送门

    Solution:

    虽说这是道$cdq$分治的基础题,但既然在练数据结构就用主席树写吧

    (其实是我$cdq$分治没学好)

    首先可以通过树状数组求出总的逆序对对数和每个数能组成的对数$cnt[i]=pre[i]+suf[i]$

    接下来如果删除了第$i$位,最多删去$cnt[i]$个逆序对,毕竟其中可能有和已删去值组成的逆序对

    那么只要求出第$i$位和删去的数组成的逆序对对数$qry$,$cnt[i]-qry$即是该次应减的值

    对于数$x$,$qry$的值可分为两部分:

    1、删除数中位置在$[1,pos[x]-1]$数值在$[x+1,n]$的个数

    2、删除数中位置在$[pos[x]+1,n]$数值在$[1,x-1]$的个数

    也就是要求已删去的数中位置在$[L,R]$间数值在$[l,r]$间的数的个数

    此类区间求某范围内数的个数的问题明显是主席树的模型

    利用类似于$Dynamic Rankings$一题中的带修改主席树的方式来解决即可

    实现时这里可以不用记录所有节点并一起移动

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int MAXN=1e5+10;
    ll res=0;
    struct PrTree{int ls,rs,cnt;}seg[MAXN*60];
    int n,m,x,rt[MAXN],dat[MAXN],pre[MAXN],suf[MAXN],pos[MAXN],bit[MAXN],tot;
    
    inline int lowbit(int x){return x&(-x);}
    void upd(int x){while(x<=n) bit[x]++,x+=lowbit(x);}
    int qry(int x){int ret=0;while(x) ret+=bit[x],x-=lowbit(x);return ret;}
    
    void Update(int &cur,int pos,int val,int l,int r)
    {
        if(!cur) cur=++tot;
        seg[cur].cnt+=val;
        if(l==r) return;int mid=(l+r)>>1;
        if(pos<=mid) Update(seg[cur].ls,pos,val,l,mid);
        else Update(seg[cur].rs,pos,val,mid+1,r);
    }
    
    int Query(int a,int b,int k,int l,int r)
    {
        if(!k) return 0;
        if(a<=l&&r<=b) return seg[k].cnt;
        int ret=0,mid=(l+r)>>1;
        if(a<=mid) ret+=Query(a,b,seg[k].ls,l,mid);
        if(b>mid) ret+=Query(a,b,seg[k].rs,mid+1,r);
        return ret;
    }
    
    ll cal(int pl,int pr,int vl,int vr)
    {
        if(vl>vr) return 0;ll ret=0;
        for(int i=pl-1;i;i-=lowbit(i))
            res-=Query(vl,vr,rt[i],1,n);
        for(int i=pr;i;i-=lowbit(i))
            res+=Query(vl,vr,rt[i],1,n);
        return ret;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&dat[i]);pos[dat[i]]=i;
            pre[i]=(i-1)-qry(dat[i]);res+=pre[i];upd(dat[i]);
        }
        memset(bit,0,sizeof(bit));
        for(int i=n;i>=1;i--)
            suf[i]=qry(dat[i]),upd(dat[i]);
        
        while(m--)
        {
            printf("%lld
    ",res);
            scanf("%d",&x);int p=pos[x];
            res-=pre[p]+suf[p]-cal(1,p-1,x+1,n)-cal(p+1,n,1,x-1);
            
            for(int i=p;i<=n;i+=lowbit(i))
                Update(rt[i],x,1,1,n);
        }
        return 0;
    }
  • 相关阅读:
    对技术的态度
    码农提高工作效率
    为什么要使用String
    Java还是程序员的金饭碗
    为什么Java7开始在数字中使用下划线
    阿里云快速搭建一个静态网站
    IDEA中Springboot项目部署到阿里云linux服务器
    Linux环境下安装宝塔面板
    阿里云服务器的购买和配置以及搭建项目教程
    linux服务器上部署springboot项目,并让他持续运行到后台
  • 原文地址:https://www.cnblogs.com/newera/p/9357352.html
Copyright © 2011-2022 走看看