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\n",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;
}

 

posted @ 2019-03-25 19:53  LLTYYC  阅读(222)  评论(0编辑  收藏  举报