一个不用在 merge_sort 里写多种情况的写法。
其实就是把每次需要 i>j 的属性倒转,使得条件变成 i<j。
/*
构造三维偏序问题
每个元素有三个属性值:下标p,值a,被删除的时间t
为了方便树状数组求前缀和,我们规定:t越小,越晚被删除,t的值域是1~n,一直没被删的元素任意分配1~n-m的t即可
那么对于元素j,我们定义res[j]表示满足下列两个条件之一的i的数量:
1.p[i]<p[j],a[i]>a[j],t[i]<t[j]
2.p[i]>p[j],a[i]<a[j],t[i]<t[j]
res[j]表示的意义就是,j参与构成的逆序对数量,其中j是这个逆序对中较早被删的元素,(为防止重复计算)
由于每个元素的t都是唯一的,我们可以用t唯一确定一个元素,我们定义s[k]表示t=k的元素的res
在t=k的元素被删除前,我们要求的就是所有t<=k的元素中逆序对的数量
分类讨论易得,这个东西就等于s[1]+s[2]+...+s[k]
求res的时候算两次三维偏序就行了,第一次把a反转,第二次把p反转即可
*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+5;
int n,m;
struct Node{
int a,t,res;
}q[N],bq[N],w[N];
int pos[N];
int tr[N];
LL ans[N];
int lowbit(int x){
return x&-x;
}
void add(int x,int v){
for(int i=x; i<=n; i+=lowbit(i)) tr[i]+=v;
}
int sum(int x){
int res=0;
for(int i=x; i; i-=lowbit(i)) res+=tr[i];
return res;
}
void merge_sort(int l,int r){
if(l>=r) return;
int mid=l+r>>1;
merge_sort(l,mid),merge_sort(mid+1,r);
int i=l,j=mid+1,k=0;
while(i<=mid&&j<=r)
if(q[i].a<q[j].a) add(q[i].t,1),w[++k]=q[i++];
else q[j].res+=sum(q[j].t),w[++k]=q[j++];
while(i<=mid) add(q[i].t,1),w[++k]=q[i++];
while(j<=r) q[j].res+=sum(q[j].t),w[++k]=q[j++];
for(i=l; i<=mid; i++) add(q[i].t,-1);
for(i=l,j=1; i<=r; i++,j++) q[i]=w[j];
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1; i<=n; i++){
scanf("%d",&q[i].a);
pos[q[i].a]=i;
}
for(int i=1,j=n; i<=m; i++,j--){
int del;
scanf("%d",&del);
q[pos[del]].t=j;
}
for(int i=1,j=n-m; i<=n; i++)
if(!q[pos[i]].t)
q[pos[i]].t=j--;
//第一次把a倒转
for(int i=1; i<=n; i++) bq[i]=q[i],q[i].a=n-q[i].a+1;
merge_sort(1,n);
for(int i=1; i<=n; i++) ans[q[i].t]+=q[i].res;
//第二次把p倒转
for(int i=1; i<=n; i++) q[i]=bq[n-i+1];
merge_sort(1,n);
for(int i=1; i<=n; i++) ans[q[i].t]+=q[i].res;
for(int i=2; i<=n; i++) ans[i]+=ans[i-1];
for(int i=n; i>=n-m+1; i--) printf("%lld\n",ans[i]);
return 0;
}