题目描述
对于序列A,它的逆序对数定义为满足 i < j,且Ai > Aj的数对(i,j)的个数。给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
题解
CDQ分治
涉及到删除一个数,怎么搞,想了也没有好的解决方法。
我们只喜欢统计某元素贡献而不会删除元素贡献。
那就把删除改为插入就行了。越早删掉的可以视为越晚插入,每有删的则视为依次从最开始插入即可。
再来考虑怎么做。
假设在某个时间点
t0
t
0
要求
p0
p
0
位置上的数
x0
x
0
的对此时答案的贡献,且保证不重复。
那么对于
p<p0
p
<
p
0
的数,当
t<t0,且x>x0
t
<
t
0
,
且
x
>
x
0
时该数有贡献。
仅仅这样够吗?
因为当前面有满足
p<p0,t>t0,x>x0
p
<
p
0
,
t
>
t
0
,
x
>
x
0
的数x存在时,
x0
x
0
对
x
x
有贡献,但这时统计不到。所以还要看某个数后面的数,把的数也算一遍贡献就行了。
并且这样不会算重,因为每个数只算了比它先出现的数,不会算重。
统计答案时,一个数的贡献会一直持续,相当于是对答案进行一个后缀加,随便差分一下就可以了。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<queue>
using namespace std;
inline int read()
{
int x=0;char ch=getchar();int t=1;
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
return x*t;
}
const int N=1e5+100;
struct node{int x;int ti;}a[N];
typedef long long ll;
int id[N];
ll ans[N];
ll anss[N];
int n,m;
node tmp[N];
int tr[2][N];
#define lowbit(a) ((a)&(-a))
inline void add(int p,int x,int k){while(p<=n) tr[k][p]+=x,p+=lowbit(p);}
inline int query(int p,int k) {int res=0;while(p) res+=tr[k][p],p-=lowbit(p);return res;}
inline void CDQ(int l,int r)
{
if(l==r) return ;
register int mid=l+r>>1;
CDQ(l,mid);CDQ(mid+1,r);
register int p=l,q=mid+1,head=l;register int res;
for(register int i=l;i<=mid;i++) add(a[i].ti,1,0);
while(p<=mid&&q<=r)
{
if(a[p].x<a[q].x){
res=query(a[p].ti,1);
ans[a[p].x]+=res;
add(a[p].ti,-1,0);
tmp[head++]=a[p++];
}
else{
res=query(a[q].ti,0);
ans[a[q].x]+=res;
add(a[q].ti,1,1);
tmp[head++]=a[q++];
}
}
while(p<=mid) {add(a[p].ti,-1,0);ans[a[p].x]+=query(a[p].ti,1);tmp[head++]=a[p++];}
for(register int i=mid+1;i<q;i++) add(a[i].ti,-1,1);
while(q<=r) tmp[head++]=a[q++];
for(register int i=l;i<=r;i++) a[i]=tmp[i];
}
int main()
{
n=read();m=read();
for(register int i=1;i<=n;i++) a[i].x=read(),a[i].ti=0,id[a[i].x]=i;
for(register int i=1;i<=m;i++) {int x=read();a[id[x]].ti=n-i+1;}
register int head=n-m;
for(register int i=1;i<=n;i++) if(a[i].ti==0) a[i].ti=head--;
CDQ(1,n);
for(register int i=1;i<=n;i++) anss[a[i].ti]+=ans[a[i].x];
for(register int i=1;i<=n;i++) anss[i]+=anss[i-1];//差分
for(register int i=n;i>=n-m+1;i--) printf("%lld\n",anss[i]);
}