• P3157 [CQOI2011]动态逆序对


    传送门

    设 $val[i]$ 为位置 $i$ 的值

    维护 $ansL[i]$ 表示位置 $i$ 的数左边所有大于 $val[i]$ 的数的数量

    维护 $ansR[i]$ 表示位置 $i$ 的数右边所有小于 $val[i]$ 的数的数量

    考虑先求出一开始总的逆序对数 $ans$

    每次删除一个数 (位置为 $p$ ) 就把 $ans$ 减去 $ansL[p]+ansR[p]$

    但是这样会多减,因为有些数在更之前就删掉了

    考虑维护这些删掉的数的贡献,发现那么我们的 $ans$ 多扣了以后还要加上之前删除的位置小于 $p$ 且大于 $val[p]$ 的数以及位置大于 $p$ 且小于 $val[p]$ 的数

    因为每次删掉相当于单点修改,查询就是区间查询,所以考虑用树状数组套动态开点权值线段树来维护

    具体看代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    const int N=2e5+7,M=3e7+7;
    int n,m;
    
    int T[N];//这个树状数组维护ansL,ansR和ans
    inline void T_add(int x,int y) { while(x<=n) T[x]+=y,x+=x&-x; }
    inline int T_sum(int x) { int res=0; while(x) res+=T[x],x-=x&-x; return res; }
    
    int rt[N],S[M],L[M],R[M],cnt;//树状数组套动态开点的权值线段树
    int pos,ql,qr,res,pd;
    inline void S_ins(int &o,int l,int r)//往线段树插入一个数
    {
        if(!o) o=++cnt; S[o]++;
        if(l==r) return;
        int mid=l+r>>1;
        if(pos<=mid) S_ins(L[o],l,mid);
        else S_ins(R[o],mid+1,r);
    }
    inline void S_query(int o,int l,int r)//在线段树中查询一个区间的数的数量
    {
        if(l>qr||r<ql||!o) return;
        if(l>=ql&&r<=qr) { res+=S[o]*pd; return; }//pd判断是+还是-
        int mid=l+r>>1;
        S_query(L[o],l,mid); S_query(R[o],mid+1,r);
    }
    
    inline int Query(int pl,int pr,int vl,int vr)//查询当前位置>=pl,<=pr,权值>=vl,<=vr的数的数量
    {
        res=0; ql=vl,qr=vr;
        pd=1; for(int i=pr;i;i-=i&-i) S_query(rt[i],1,n);
        pd=-1; for(int i=pl-1;i;i-=i&-i) S_query(rt[i],1,n);//注意pl-1因为是要减去的不包括pl
        return res;
    }
    int ansL[N],ansR[N];
    ll ans;
    int val[N],id[N];
    int main()
    {
        n=read(),m=read();
        for(int i=1;i<=n;i++)
        {
            val[i]=read(),id[val[i]]=i;
            ansL[i]=(i-1)-T_sum(val[i]);
            ans+=ansL[i]; T_add(val[i],1);
        }
        for(int i=1;i<=n;i++) T[i]=0;
        for(int i=n;i;i--) ansR[i]=T_sum(val[i]-1),T_add(val[i],1);
        int a,p;
        while(m--)
        {
            printf("%lld
    ",ans); a=read(); p=id[a];
            ans-=ansL[p]+ansR[p]-Query(1,p,a+1,n)-Query(p+1,n,1,a-1);//动态维护ans
            pos=a; while(p<=n) S_ins(rt[p],1,n),p+=p&-p;
        }
        return 0;
    }
  • 相关阅读:
    基于 cobbler 实现自动安装 linux 系统
    自动安装 linux 系统
    从12306网站新验证码看Web验证码设计与破解
    用java实现删除文件夹里的所有文件
    本机访问其它电脑上的oracle数据库
    powerdesigner 15 如何导出sql schema
    使用PowerDesigner建立数据库模型
    com.google.gson.stream.MalformedJsonException的解决办法
    Spring注解详解
    nginx中文手册内容说明
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/10596047.html
Copyright © 2020-2023  润新知