题意:给一个序列,每次交换(a_l,a_r),并且询问交换后的整个序列的逆序对数
分块+二分
刚开始的逆序对数可以直接用归并排序求出来,我们先更新答案再交换,考虑每次交换的(a_l,a_r),会影响逆序对的只可能是([l,r])这个区间的数,如果单独拿出之间的一个数(a_i(l+1le ile r-1))来说,对答案则有四种可能的影响
- (a_i>a_l o ans++)
(a_i)比(a_l)大,(a_l)和(a_r)交换之后(a_l)下标比(a_i)大,逆序对数(+1)
- (a_i<a_l o ans--)
(a_i)比(a_l)小,已经是逆序对,(a_l)和(a_r)交换,逆序对数(-1)
- (a_i<a_r o ans++)
(a_i)比(a_r)小,(a_l)和(a_r)交换之后(a_r)下标比(a_i)小,逆序对数(+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;
}