【题解】
将两堆物品拼接到一起,物品的移动次数等价于中间的"断点"的移动距离之和
通过排序预处理出每次删除后的下一个该删除的位置
每个物品代表一条长度为1的线段,该物品删除后,线段长度改为0
然后两点之间的距离就转化为了区间和,用树状数组维护即可
【代码】
#include<stdio.h>
#include<stdlib.h>
typedef long long LL;
int a[100005],b[100005],c[100005];
int n;
void jh(int* a,int* b)
{
int t=*a;
*a=*b;
*b=t;
}
void xg(int p,int i)
{
for(;i<=n;i+=i&(-i))
c[i]+=p;
}
LL cx(int i)
{
int ans=0;
for(;i>0;i-=i&(-i))
ans+=c[i];
return (LL)ans;
}
void kp(int low,int high)
{
int i=low,j=high,mid=a[(i+j)/2];
while(i<j)
{
while(a[i]>mid) i++;
while(a[j]<mid) j--;
if(i<=j)
{
jh(&a[i],&a[j]);
jh(&b[i],&b[j]);
i++;
j--;
}
}
if(j>low) kp(low,j);
if(i<high) kp(i,high);
}
int main()
{
LL ans=0;
int n1,n2,i,p;//p:当前断点在第几个元素之前
scanf("%d%d",&n1,&n2);
for(i=n1;i>=1;i--)
scanf("%d",&a[i]);
for(i=n1+1;i<=n1+n2;i++)
scanf("%d",&a[i]);
p=n1+1;
n=n1+n2;
for(i=1;i<=n;i++)
{
b[i]=i;
xg(1,i);
}
kp(1,n);
for(i=1;i<=n;i++)
{
if(p>b[i])
{
ans+=cx(p-1)-cx(b[i]);
p=b[i]+1;
}
else
{
ans+=cx(b[i]-1)-cx(p-1);
p=b[i];
}
xg(-1,b[i]);
}
printf("%lld",ans);
return 0;
}