Codeforces785E - Anton and Permutation

Portal

Description

对一个长度为\(n(n\leq2\times10^5)\)的数列\(a\)进行\(m(m\leq5\times10^4)\)次操作,数列初始时为\(\{1,2,...,n\}\)。每次操作交换数列中的两个数\(a_L\)\(a_R\),并询问此时数列\(a\)中的逆序对数。

Solution

交换\(a_L\)\(a_R\)时,会影响逆序对数的只有下标在\((L,R)\)之间,数值在\(a_L\)\(a_R\)之间的数(钦定\(L<R\))。设这样的数有\(k\)个,那么若\(a_L<a_R\),逆序对数会增加\(2k+1\);若\(a_L>a_R\),逆序对数会减少\(2k+1\)
所以只要使用一种数据结构,支持单点修改和查询区间内数值在某个范围内的数的个数。分块即可解决这个问题。维护每个块内的数有序,那么就可以通过二分查找以\(O(log\sqrt n)\)求出块内满足条件的数的个数。对于修改,修改之后将所在块再次排序即可。

时间复杂度\(O(m\sqrt nlog\sqrt n)。\)

Code

//Anton and Permutation
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long lint;
inline char gc()
{
    static char now[1<<16],*S,*T;
    if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;}
    return *S++;
}
inline int read()
{
    int x=0; char ch=gc();
    while(ch<'0'||'9'<ch) ch=gc();
    while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc();
    return x;
}
int const N=2e5+1e3;
int n,m,n0,a[N];
int blk[N],fr[N],to[N],b[N];
int query(int t,int x,int y)
{
    int L=upper_bound(b+fr[t],b+to[t]+1,x)-b;
    int R=lower_bound(b+fr[t],b+to[t]+1,y)-b-1;
    return R-L+1;
}
void update(int t)
{
    for(int i=fr[t];i<=to[t];i++) b[i]=a[i];
    sort(b+fr[t],b+to[t]+1);
}
int main()
{
    n=read(),m=read(); n0=sqrt(n);
    for(int i=1;i<=n;i++) a[i]=b[i]=i;
    for(int i=1;i<=n;i++) blk[i]=(i-1)/n0+1;
    for(int i=1;i<=blk[n];i++) fr[i]=(i-1)*n0+1,to[i]=i*n0;
    to[blk[n]]=n;
    lint ans=0;
    for(int i=1;i<=m;i++)
    {
        int L=read(),R=read(); if(L>R) swap(L,R);
        if(L==R) {printf("%lld\n",ans); continue;}
        int x=a[L],y=a[R]; lint res=0,f=1;
        if(x>y) swap(x,y),f=-1;
        if(blk[L]==blk[R]) for(int i=L;i<=R;i++) res+=(x<a[i]&&a[i]<y);
        else
        {
            for(int i=L;i<=to[blk[L]];i++) res+=(x<a[i]&&a[i]<y);
            for(int t=blk[L]+1;t<=blk[R]-1;t++) res+=query(t,x,y);
            for(int i=fr[blk[R]];i<=R;i++) res+=(x<a[i]&&a[i]<y);
        }
        ans+=2*res*f; if(a[L]<a[R]) ans++; else ans--;
        swap(a[L],a[R]); update(blk[L]),update(blk[R]);
        printf("%lld\n",ans);
    }
    return 0;
}

P.S.

要用long long来保存逆序对数。
存在\(L=R\)的情况,可以特判一下。

转载于:https://www.cnblogs.com/VisJiao/p/8491372.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值