题解 CF785E 【Anton and Permutation】

考虑用分块解决这个题,一次交换对当前逆序对个数的影响是,加上两倍的在区间\([l+1,r-1]\)中比\(a_r\)小的元素个数,减去两倍的在区间\([l+1,r-1]\)中比\(a_l\)小的元素个数,再根据\(a_l\)\(a_r\)的大小关系决定这两个位置对答案的影响。

可以用\(vector\)来维护每个块内元素有序,然后就可以支持询问了。

\(code:\)

#include<bits/stdc++.h>
#define maxn 200010
#define lower(a,x) lower_bound(ve[a].begin(),ve[a].end(),x)
#define upper(a,x) upper_bound(ve[a].begin(),ve[a].end(),x)
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,k,S;
int bel[maxn],a[maxn];
ll ans;
vector<int> ve[maxn];
void change(int l,int r)
{
    if(bel[l]!=bel[r])
    {
        ve[bel[l]].erase(lower(bel[l],a[l])),ve[bel[l]].insert(upper(bel[l],a[r]),a[r]);
        ve[bel[r]].erase(lower(bel[r],a[r])),ve[bel[r]].insert(upper(bel[r],a[l]),a[l]);
    }
    swap(a[l],a[r]);
}
int query(int l,int r,int v)
{
    if(l>r) return 0;
    int cnt=0;
    for(int i=l;i<=min(S*bel[l],r);++i) cnt+=(a[i]<v);
    if(bel[l]==bel[r]) return cnt;
    for(int i=S*(bel[r]-1)+1;i<=r;++i) cnt+=(a[i]<v);
    for(int i=bel[l]+1;i<=bel[r]-1;++i) cnt+=lower(i,v)-ve[i].begin();
    return cnt;
}
int main()
{
    read(n),read(k),S=sqrt(n);
    for(int i=1;i<=n;++i) a[i]=i,bel[i]=(i-1)/S+1,ve[bel[i]].push_back(a[i]);
    while(k--)
    {
        int l,r;
        read(l),read(r);
        if(l>r) swap(l,r);
        if(l==r)
        {
            printf("%lld\n",ans);
            continue;
        }
        ans+=2*(query(l+1,r-1,a[r])-query(l+1,r-1,a[l]));
        if(a[l]<a[r]) ans++;
        else ans--;
        change(l,r),printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2020-05-14 00:25  lhm_liu  阅读(234)  评论(0编辑  收藏  举报