洛谷 P1975 [国家集训队]排队

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

分块+二分

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

  1. (a_i>a_l o ans++)

(a_i)(a_l)大,(a_l)(a_r)交换之后(a_l)下标比(a_i)大,逆序对数(+1)

  1. (a_i<a_l o ans--)

(a_i)(a_l)小,已经是逆序对,(a_l)(a_r)交换,逆序对数(-1)

  1. (a_i<a_r o ans++)

(a_i)(a_r)小,(a_l)(a_r)交换之后(a_r)下标比(a_i)小,逆序对数(+1)

  1. (a_i>a_r o ans--)

(a_i)(a_r)大,已经是逆序对,(a_l)(a_r)交换,逆序对数(-1)

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

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

这样每次交换后对(a_l)(a_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
",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
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/sdlang/p/13068067.html