戳我看题面
常规操作:离线后删除改成插入(倒着做)
问题就变成了插入一个数,求逆序对
求逆序对是cdq分治,所以插入一个数求逆序对多半也是cdq分治
构造三元组,
表示时间,
表示位置,
表示数的大小
新插入一个数带来的影响无疑是
且(
,
或者
,
)
记下来后求一前缀和就搞定了
#include
#define ll long long
using namespace std;
const int N=1e6+5;
int n,m,t[N],c,a[N];
bool f[N];
ll ans[N];
struct A{int id,a,b,c; }qq[N],q[N],q1[N],q2[N];
void work2(int l,int r)
{
if(l==r) return;
int mid=l+r>>1;
work2(l,mid),work2(mid+1,r);
int i=l,j=mid+1,k=l,y=0;
for(int i=l;i<=mid;i++)
if(q1[i].a==0) y++;
while(i<=mid&&j<=r)
{
if(q1[i].c<=q1[j].c)
{
if(q1[i].a==0) y--;
q2[k++]=q1[i++];
} else
{
if(q1[j].a==1) ans[q1[j].id]+=y;
q2[k++]=q1[j++];
}
}
while(i<=mid) q2[k++]=q1[i++];
while(j<=r) q2[k++]=q1[j++];
for(int i=l;i<=r;i++) q1[i]=q2[i];
}
void work1(int l,int r)
{
if(l==r) return;
int mid=l+r>>1;
work1(l,mid),work1(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid&&j<=r)
{
if(q[i].b<=q[j].b) q[i].a=0,q1[k++]=q[i++];
else q[j].a=1,q1[k++]=q[j++];
}
while(i<=mid) q[i].a=0,q1[k++]=q[i++];
while(j<=r) q[j].a=1,q1[k++]=q[j++];
for(int i=l;i<=r;i++) q[i]=q1[i];
work2(l,r);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
c=n;
for(int i=1;i<=m;i++)
{
int x; scanf("%d",&x);
qq[c]=(A){i-1,c,x,a[x]}; f[x]=1;
c--;
}
for(int i=1;i<=n;i++)
if(!f[i]) qq[c]=(A){m,c,i,a[i]},c--;
for(int i=1;i<=n;i++) q[i]=qq[i];
work1(1,n);
for(int i=1;i<=n;i++)
q[i].id=qq[i].id,q[i].a=qq[i].a,q[i].b=qq[i].c,q[i].c=qq[i].b;
work1(1,n);
for(int i=m-1;i>=0;i--) ans[i]+=ans[i+1];
for(int i=0;i<=m;i++)
printf("%lld%c",ans[i],(i==m)?'\n':' ');
return 0;
}