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