题解 P1975 【[国家集训队]排队】

· · 题解

似乎没人用stl啊,那我来一发优美stl好了qwq

题意:给一个序列,每次交换a_l,a_r,并且询问交换后的整个序列的逆序对数

刚开始的逆序对数可以直接用归并排序求出来,我们先更新答案再交换,考虑每次交换的a_l,a_r,会影响逆序对的只可能是[l,r]这个区间的数,如果单独拿出之间的一个数a_i(l+1\le i\le r-1)来说,对答案则有四种可能的影响

  1. a_i>a_l\to ans++
a_i$比$a_l$大,$a_l$和$a_r$交换之后$a_l$下标比$a_i$大,逆序对数$+1
  1. a_i<a_l\to ans--
a_i$比$a_l$小,已经是逆序对,$a_l$和$a_r$交换,逆序对数$-1
  1. a_i<a_r\to ans++
a_i$比$a_r$小,$a_l$和$a_r$交换之后$a_r$下标比$a_i$小,逆序对数$+1
  1. a_i>a_r\to ans--
a_i$比$a_r$大,已经是逆序对,$a_l$和$a_r$交换,逆序对数$-1

那么我们用分块来维护,对于在同一个块或相邻块的,暴力枚举a_i更新答案

然后考虑在每个块里维护这个块的有序序列,每次访问到这个块的时候,直接二分查找更新答案,边角的数直接枚举更新就好了

这样每次交换后对a_la_r调整一下所在块的有序序列就好了

注意询问的l,r可能l>r所以要交换

蒟蒻也不会算块的大小什么的,常数还大的一批,就这样吧qwq

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <vector>
#define N 20000
#define rep(i,s,t) for (register int i=s;i<=t;i++)
#define drep(i,s,t) for (register int i=s;i>=t;i--)
using namespace std;
int n,a[N+5],data[N+5],m,bs,blo[N+5],na[N+5],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&&na[p]<=na[q])
                data[it++]=na[p++];
            else
            {
                data[it++]=na[q++];
                ans+=mid-p+1;
            }
        }
        rep(i,l,r)
            na[i]=data[i];
    }
}
void com(int x,int l,int r)
{
    ans+=a[x]>a[l];
    ans-=a[x]<a[l];
    ans+=a[x]<a[r];
    ans-=a[x]>a[r];
}
void reset(int x)
{
    p[x].clear();
    rep(i,(x-1)*bs+1,x*bs)
        p[x].push_back(a[i]);
    sort(p[x].begin(),p[x].end());
}
void exc(int l,int r)
{
    swap(a[l],a[r]);
    reset(blo[l]);
    reset(blo[r]);
}
void calc(int l,int r)
{
    if (a[l]==a[r])
        return;
    ans+=(a[l]<a[r]);
    ans-=(a[l]>a[r]);
    if (blo[r]-blo[l]<=1)
    {
        rep(i,l+1,r-1)
            com(i,l,r);
    }
    else
    {
        rep(i,l+1,blo[l]*bs)
            com(i,l,r);
        rep(i,(blo[r]-1)*bs+1,r-1)
            com(i,l,r);
        rep(i,blo[l]+1,blo[r]-1)
        {
            ans+=p[i].end()-upper_bound(p[i].begin(),p[i].end(),a[l]);
            ans-=lower_bound(p[i].begin(),p[i].end(),a[l])-p[i].begin();
            ans+=lower_bound(p[i].begin(),p[i].end(),a[r])-p[i].begin();
            ans-=p[i].end()-upper_bound(p[i].begin(),p[i].end(),a[r]);
        }
    }
    exc(l,r);
}
int main()
{
    scanf("%d",&n);
    rep(i,1,n)
        scanf("%d",&a[i]),na[i]=data[i]=a[i];
    sort(data+1,data+n+1);
    bs=sqrt(n);    
    rep(i,1,n)
    {
        blo[i]=(i-1)/bs+1;        
        na[i]=a[i]=lower_bound(data+1,data+n+1,a[i])-data;
        p[blo[i]].push_back(a[i]);
    }
    rep(i,1,blo[n])
        sort(p[i].begin(),p[i].end());
    merge_sort(1,n);
    printf("%d\n",ans);
    scanf("%d",&m);
    int l,r;
    rep(i,1,m)
    {
        scanf("%d%d",&l,&r);
        if (l>r)
            swap(l,r);
        calc(l,r);
        printf("%d\n",ans);
    }
    return 0;
}