洛谷 P3157 [CQOI2011]动态逆序对

对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。

可以值域分块,块套树状数组,树套树

不过用序列分块(+vector)一样能水过这道题

考虑删去一个点(x)对答案产生的影响,拿下面的数列来说

[1,2……x……n-1,n ]

对于区间([1,x-1])(a_i>a_x)会产生逆序对

对于区间([x+1,n])(a_i<a_x)会产生逆序对

那么每次删点后统计一下(x)两侧满足条件的数就好了

我们对序列分块,同一个块里的用(vector)排好序,和(x)在不同块的二分查找更新答案,和(x)在同一个块的暴力枚举更新答案,每次删点的时候在(vector)里删除点就好了

复杂度大约是(O(Mlog(N)sqrt{N})),吸吸氧就过了

Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector>
#define N 100000
#define rep(i,s,t) for (register int i=s;i<=t;i++)
#define drep(i,s,t) for (register int i=t;i>=s;i--)
#define il inline
using namespace std;
int n,m,a[N+5],data[N+5],bs,blo[N+5],L[N+5],R[N+5],na[N+5],d[N+5],id[N+5],cnt;
long long ans;
vector <int> p[N+5];
void merge_sort(int l,int r)
{
    if (r-l>0)
    {
        int it=l,mid=l+r>>1,p=l,q=mid+1;
        merge_sort(l,mid);
        merge_sort(mid+1,r);
        while (p<=mid||q<=r)
        {
            if (q>r||p<=mid&&data[p]<=data[q])
                na[it++]=data[p++];
            else
            {
                na[it++]=data[q++];
                ans+=(long long)mid-p+1;
            }
        }
        rep(i,l,r)
            data[i]=na[i];
    }
}
il void del(int x)
{
    d[x]=1;
    vector <int>::iterator it=lower_bound(p[blo[x]].begin(),p[blo[x]].end(),a[x]);
    p[blo[x]].erase(it);
}
il void calc(int x)
{
    rep(i,1,blo[x]-1)
        ans-=(long long)(p[i].end()-upper_bound(p[i].begin(),p[i].end(),a[x]));
    rep(i,L[blo[x]],x-1)
        if (a[i]>a[x]&&!d[i])
            ans--;
    rep(i,x+1,R[blo[x]])
        if (a[i]<a[x]&&!d[i])
            ans--;
    rep(i,blo[x]+1,blo[n])
        ans-=(long long)(lower_bound(p[i].begin(),p[i].end(),a[x])-p[i].begin());
}
il int read()
{
	int X(0),w(0);char ch(0);
	while (!isdigit(ch))w|=ch=='-',ch=getchar();
	while (isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
	return w?-X:X;
}
int main()
{
    n=read();
    m=read();
    bs=sqrt(n);
    rep(i,1,n)
    {
        a[i]=read();
        data[i]=a[i];
        id[a[i]]=++cnt;
        blo[i]=(i-1)/bs+1;
        if (!L[blo[i]])
            L[blo[i]]=i;
        R[blo[i]]=i;
        p[blo[i]].push_back(a[i]);
    }
    merge_sort(1,n);
    rep(i,1,blo[n])
        sort(p[i].begin(),p[i].end());
    int x;
    rep(i,1,m)
    {
        printf("%lld
",ans);
        x=read();
        del(id[x]);
        calc(id[x]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sdlang/p/13068080.html