Loading

1020. 逆序对统计

Description

Dramatic是在太菜了。最近,他学习了有关逆序对的知识,并且掌握了计算一个序列逆序对个数的高效算法,因此,他兴冲冲的跑去向 YY 牛炫耀。YY 牛对此不屑一顾,并打击 Dramatic 说:“这是在太小儿科了!”Dramatic 很不甘心,于是在他的强烈要求下,YY 牛给他出了一道跟逆序对有关的“难题”(显然,对于YY牛来说是简单题)。题目是这样的:YY 牛首先给 Dramatic 一个长度为 N 的整数序列 A。接下来,YY 牛会对 Dramatic 说:把 A 的第 i 个数字改成 j,同时告诉我现在 A 中逆序对的个数。重复了若干次之后,Dramatic 已经算得头晕眼花,支撑不住了。然而,YY 牛的命令一共有 M 个!为了解决这个问题,Dramatic 只好你,你能够帮助 Dramatic 解决YY牛的“难题”吗?

友情提示:如果有两个数字 i,j 满足 i<j 且 Ai>Aj,则它们被称为一个逆序对。

Solution

序列问题,想到了 cdq 分治,但我不会。

发现 \(m\) 最大只有 \(10000\),说明更改过的数不会超过 \(10000\)。可以利用这个性质。

每次更改时,先求出这个位置对其他所有数的改前和改后的贡献。这个可以使用主席树来做。

现在考虑对更改和更改之间计算,不妨暴力一点,直接 \(\mathcal O(m^2)\) 计算。

总时间复杂度 \(\mathcal O(n\log n+m^2)\),可以通过 2s 的时限。

注意卡卡空间。

Code

#include<cstdio>
#define N 250005
#define M 10005
#define MX 500005
#define ll long long
using namespace std;
int n,m,num,a[N],aa[N],rt[N],tr[MX*10+N][3],pos[M],val[M],sta[M];
ll res;
bool bj[N];
int modify(int l,int r,int lst,int p)
{
    int now=++num;
    tr[now][0]=tr[lst][0]+1;
    if (l==r) return now;
    int mid=(l+r)>>1;
    if (p<=mid)
    {
        tr[now][1]=modify(l,mid,tr[lst][1],p);
        if (!tr[lst][2]) tr[now][2]=++num;
        else tr[now][2]=tr[lst][2];
    }
    else
    {
        tr[now][2]=modify(mid+1,r,tr[lst][2],p);
        if (!tr[lst][1]) tr[now][1]=++num;
        else tr[now][1]=tr[lst][1];
    }
    return now;
}
int query(int l,int r,int x,int y,int p,int q)
{
    if (q<l||p>r) return 0;
    if (l>=p&&r<=q) return tr[y][0]-tr[x][0];
    int mid=(l+r)>>1;
    return query(l,mid,tr[x][1],tr[y][1],p,q)+query(mid+1,r,tr[x][2],tr[y][2],p,q);
}
int main()
{
    freopen("T4.in","r",stdin);
    freopen("T4.out","w",stdout);
    scanf("%d",&n);
    for (int i=1;i<=n;++i)
    {
        scanf("%d",&a[i]);aa[i]=a[i];
        rt[i]=modify(1,MX,rt[i-1],a[i]);
        res+=query(1,MX,rt[0],rt[i],a[i]+1,MX);
    }
    scanf("%d",&m);
    for (int i=1;i<=m;++i)
    {
        scanf("%d%d",&pos[i],&val[i]);
        if (pos[i]>1)
        {
            res-=query(1,MX,rt[0],rt[pos[i]-1],a[pos[i]]+1,MX);
            res+=query(1,MX,rt[0],rt[pos[i]-1],val[i]+1,MX);
        }
        if (pos[i]<n)
        {
            res-=query(1,MX,rt[pos[i]],rt[n],1,a[pos[i]]-1);
            res+=query(1,MX,rt[pos[i]],rt[n],1,val[i]-1);
        }
        if (!bj[pos[i]]) bj[pos[i]]=true,sta[++sta[0]]=pos[i];
        for (int j=1;j<=sta[0];++j)
        {
            if (sta[j]<pos[i])
            {
                if (a[pos[i]]<aa[sta[j]]) ++res;
                if (a[pos[i]]<a[sta[j]]) --res;
                if (val[i]<aa[sta[j]]) --res;
                if (val[i]<a[sta[j]]) ++res;
            }
            if (sta[j]>pos[i])
            {
                if (a[pos[i]]>aa[sta[j]]) ++res;
                if (a[pos[i]]>a[sta[j]]) --res;
                if (val[i]>aa[sta[j]]) --res;
                if (val[i]>a[sta[j]]) ++res;
            }
        }
        a[pos[i]]=val[i];
        printf("%lld\n",res);
    }
    return 0;
}
posted @ 2022-04-09 17:03  Thunder_S  阅读(45)  评论(0编辑  收藏  举报