使用樹狀陣列求出初態下出f[i]、g[i]表示位置小(大)於i且值大(小)於a[i]的元素個數。顯然ans|初=sum f[i]=sum g[i]。
考慮第一個刪去的點x,刪去以後,ans減少f[x]+g[x];再考慮第二個刪去的點y,刪去以後,ans減少f[y]+g[y]?不,f[y]、g[y]中可能算上了x(此題裡是必然),這{x,y}這一對已經在上一次刪除時減掉了,所以ans減少f[y]+g[y]的同時,還應加上已刪除的點中與y構成的“逆序對數”。以後刪除的點同理;
假設當前正在刪除元素x,設元素到位置的對映為id[x],設f1、g1為在已刪的點中與x相比位置小(大)於i且值更大(小)於的點的個數,那麼ans應該為ans-f[x]-g[x]+f1+g1。現考慮如何快速計算f1、g1。以計算f1為例:
一:將刪除的點放在新序列b的相應位置,每次掃描b[1~id[x]]中有多少滿足b[i]>x的點。
二:不放將序列b擴充為矩陣b[i,j],b[i,j]表示位置為i,值為j的元素是否已經被刪除。每次n^2求矩陣b[1~id[x], x+1,n]的和
三:二中的b大小為n*n顯然不行。考慮將b[i]改為一顆權值線段樹(求一段值域內的元素個數),這樣大小變為nlogn。
四:每一次刪除一個點,會修改線段樹b[id[x]~n],用時過久。不放對所有權值線段樹的同一個區間求字首和(例項:主席樹)查詢變為作差;這時修改線段樹b[id[x]~n]相當於是單點修改更新字首和,考慮使用樹狀陣列來完成。
就是樹狀陣列套權值線段樹了。
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m,tot;
long long ans;
int root[N],bit[N],id[N],a[N],f[N],g[N];
struct edge {
int ls,rs,sum;
} t[N*30];
void update(int&x,int l,int r,int w) {
if(!x) x=++tot;
t[x].sum+=(w!=0);
if(l==r) return;
int mid=(l+r)>>1;
if(w<=mid) update(t[x].ls,l,mid,w);
else update(t[x].rs,mid+1,r,w);
}
int L[N],cntl,R[N],cntr;
int f1(int x,int y,int w) {
cntl=cntr=0, x--;
for(; x>0; x-=(x&-x)) L[++cntl]=root[x];
for(; y>0; y-=(y&-y)) R[++cntr]=root[y];
int l=1, r=n, ret=0;
while(l!=r) {
int mid=(l+r)>>1;
if(w<=mid) { //右區間全滿
for(int i=1; i<=cntl; ++i) ret-=t[t[L[i]].rs].sum;
for(int i=1; i<=cntr; ++i) ret+=t[t[R[i]].rs].sum;
for(int i=1; i<=cntl; ++i) L[i]=t[L[i]].ls;
for(int i=1; i<=cntr; ++i) R[i]=t[R[i]].ls;
r=mid;
} else {
for(int i=1; i<=cntl; ++i) L[i]=t[L[i]].rs;
for(int i=1; i<=cntr; ++i) R[i]=t[R[i]].rs;
l=mid+1;
}
}
return ret;
}
int g1(int x,int y,int w) {
cntl=cntr=0, x--;
for(; x>0; x-=(x&-x)) L[++cntl]=root[x];
for(; y>0; y-=(y&-y)) R[++cntr]=root[y];
int l=1, r=n, ret=0;
while(l!=r) {
int mid=(l+r)>>1;
if(mid<w) { //左區間全滿
for(int i=1; i<=cntl; ++i) ret-=t[t[L[i]].ls].sum;
for(int i=1; i<=cntr; ++i) ret+=t[t[R[i]].ls].sum;
for(int i=1; i<=cntl; ++i) L[i]=t[L[i]].rs;
for(int i=1; i<=cntr; ++i) R[i]=t[R[i]].rs;
l=mid+1;
} else {
for(int i=1; i<=cntl; ++i) L[i]=t[L[i]].ls;
for(int i=1; i<=cntr; ++i) R[i]=t[R[i]].ls;
r=mid;
}
}
return ret;
}
int sum(int x,int y=0) {
for(; x>0; x-=(x&-x)) y+=bit[x];
return y;
}
void add(int x,int y) {
for(; x<=n; x+=(x&-x)) bit[x]+=y;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=n; ++i) {
scanf("%d",&a[i]);
id[a[i]]=i;
f[i]=sum(n)-sum(a[i]);
add(a[i],1);
ans+=f[i];
}
for(int i=1; i<=n; ++i) bit[i]=0;
for(int i=n; i>=1; --i) {
g[i]=sum(a[i]);
add(a[i],1);
}
update(root[0],1,n,0);
for(int x; m--; ) {
scanf("%d",&x);
printf("%lld
",ans);
ans-=f[id[x]]-f1(1,id[x],x)+g[id[x]]-g1(id[x],n,x);
for(int i=id[x]; i<=n; i+=(i&-i)) {
update(root[i],1,n,x);
}
}
return 0;
}