题解的做法,先把bi从小到大排序,因为pi随bi递增,因此对于当前的一段b[L,R],先求bL+R2的最优位置,再递归到左右子区间求解。这样左右子区间扫描的长度之和就只有当前区间的长度。又因为递归了logn层,因此时间复杂度也是O(nlogn)的。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+4;
int a[N],b[N],bb[N],aa[N<<1];
#define ll long long
ll sum;
void fun(int l,int r,int L,int R)
{
if(l>r||L>R)return;
int mid=l+r>>1;
int t = b[mid];
int numl=0,numr=0;///右侧形成的逆序对
for(int i=L;i<=R;++i)
if(a[i]<t)numr++;
int idx=L,minn=numr;
for(int i=L+1;i<=R;++i)
{
if(a[i-1]>t)numl++;
else if(a[i-1]<t)numr--;
if(numl+numr<minn)
{
idx=i;
minn=numl+numr;
}
}
bb[mid]=idx;
fun(l,mid-1,L,idx);
fun(mid+1,r,idx,R);
}
int c[N<<1];
inline void msort(int l,int r)
{
if(l==r)return;
int mid=(l+r)>>1;
msort(l,mid);msort(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(aa[i]<=aa[j])
c[k++]=aa[i++];
else
{
c[k++]=aa[j++];
sum+=(mid-i+1);
}
}
while(i<=mid)c[k++]=aa[i++];
while(j<=r)c[k++]=aa[j++];
for(i=l;i<=r;i++)aa[i]=c[i];
}
int main()
{
ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int T;cin >> T;
while(T--)
{
sum=0;
int n,m;
cin >> n >> m;
for(int i=1;i<=n;++i)
cin >> a[i];
a[n+1]=1e9;
for(int i=1;i<=m;++i)
cin >> b[i];
sort(b+1,b+1+m);
fun(1,m,1,n+1);
int cnt=0;
for(int i=1,j=1;i<=n+1;++i)
{
while(bb[j]==i&&j<=m)
{
aa[++cnt]=b[j];
j++;
}
aa[++cnt]=a[i];
}
msort(1,n+m);
cout << sum << endl;
}
}