本题可以使用分治完成。
二维偏序
根据偏序的定义,逆序对是一个二维偏序,但这个二维偏序比较特殊:
以上两种情况都符合这个二维偏序。
三维偏序
但带修改二维偏序怎么做?
我们将删除操作视为插入操作。
则没有没删除的插入时间为,第
个被删除的,插入时间为
将插入时间作为第一维,数列位置为第二维,数值为第三维。
做三维偏序即可。
注意由于逆序对的定义,三维偏序仍是两种情况。
分治
简要介绍一下分治。
分治是一种分治算法(废话),是一个叫做陈丹琪的女选手在
(记不清了)年提出的。当时提出时是用于优化一类
问题的。后来
分治被主要用于解决三维偏序问题。
分治思想类似于归并排序。归并排序每次将区间
划分为
和
考虑三维偏序问题模型,对
有贡献需要满足
。
分治先将
升序排序,再进行归并排序,使
有序。
考虑区间,当完成左右区间的归并排序后,由于一开始先对
进行了排序,则
,一定有
,这时候分别维护左区间和右区间指针,同时用树状数组维护值即可。
具体请见【模板】三维偏序(陌上花开)题解区。
#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;
} 
京公网安备 11010502036488号