本题可以使用分治完成。
二维偏序
根据偏序的定义,逆序对是一个二维偏序,但这个二维偏序比较特殊:
以上两种情况都符合这个二维偏序。
三维偏序
但带修改二维偏序怎么做?
我们将删除操作视为插入操作。
则没有没删除的插入时间为,第个被删除的,插入时间为
将插入时间作为第一维,数列位置为第二维,数值为第三维。
做三维偏序即可。
注意由于逆序对的定义,三维偏序仍是两种情况。
分治
简要介绍一下分治。
分治是一种分治算法(废话),是一个叫做陈丹琪的女选手在(记不清了)年提出的。当时提出时是用于优化一类问题的。后来分治被主要用于解决三维偏序问题。
分治思想类似于归并排序。归并排序每次将区间划分为和
考虑三维偏序问题模型,对有贡献需要满足。
分治先将升序排序,再进行归并排序,使有序。
考虑区间,当完成左右区间的归并排序后,由于一开始先对进行了排序,则,一定有,这时候分别维护左区间和右区间指针,同时用树状数组维护值即可。
具体请见【模板】三维偏序(陌上花开)题解区。
#include<bits/stdc++.h> using namespace std; #define int long long int n,m,tmp; struct node{ int a,b,c,ans; }a[40007]; int anss[40007]; template<typename Tp> void read(Tp &x){ x=0;char ch=1;int fh; while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar(); if(ch=='-'){ ch=getchar();fh=-1; } else fh=1; while(ch>='0'&&ch<='9'){ x=(x<<1)+(x<<3)+ch-'0'; ch=getchar(); } x*=fh; } struct BIT{ int c[40007]; void change(int p,int k){ while(p<=40000){ c[p]+=k;p+=(p&(-p)); } } int query(int p){ int re=0; while(p){ re+=c[p];p-=(p&(-p)); } return re; } }T; bool comp(node a,node b){ if(a.a!=b.a) return a.a<b.a; if(a.b!=b.b) return a.b<b.b; return a.c<b.c; } bool cmp(node a,node b){ if(a.b!=b.b) return a.b<b.b; return a.c<b.c; } bool ***(node a,node b){ if(a.b!=b.b) return a.b>b.b; return a.c>b.c; } void cdq(int l,int r){ if(l==r) return; int mid=(l+r)>>1; cdq(l,mid);cdq(mid+1,r); sort(a+l,a+mid+1,cmp);sort(a+mid+1,a+r+1,cmp); int i,j=l,tot=0; for(i=mid+1;i<=r;i++){ while(j<=mid&&a[j].b<=a[i].b){ T.change(a[j].c,1);++j;++tot; } a[i].ans+=tot-T.query(a[i].c); } for(i=l;i<j;i++) T.change(a[i].c,-1); sort(a+l,a+mid+1,***);sort(a+mid+1,a+r+1,***); for(i=mid+1,j=l;i<=r;i++){ while(j<=mid&&a[j].b>=a[i].b){ T.change(a[j].c,1);++j; } a[i].ans+=T.query(a[i].c); } for(i=l;i<j;i++) T.change(a[i].c,-1); } bool fake(node a,node b){ return a.c<b.c; } void lsh(){ sort(a+1,a+n+1,fake); for(register int i=1;i<=n;i++) a[i].c=i; } signed main(){ read(n);read(m); for(register int i=1;i<=n;i++){ read(a[i].c);a[i].a=1,a[i].b=i; } for(register int i=1;i<=m;i++){ read(tmp);a[tmp].a=m-i+2; } lsh(); sort(a+1,a+n+1,comp); cdq(1,n); for(register int i=1;i<=n;i++) anss[a[i].a]+=a[i].ans; for(int i=1;i<=n;i++)anss[i]+=anss[i-1]; for(int i=m+1;i>0;i--)printf("%lld%c",anss[i]," \n"[i==1]); return 0; }