带修主席树。
脑补一下,每个数对逆序对数的贡献就是前面的比它大的加上后面的比它小的,这样就可以套带修主席树的板子,找一下在它前面删去的比它大的,找一下在它后面比它小的数的个数就行了。
UPD:BZOJ上T了,发现t[]开的太大了,memset的时候直接挂。。。认真算空间Orz
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=100005;
int n,m,a[N],t[N*10],f[N],pos[N],g[N],x[N],y[N],rt[N];
long long ans;
void add(int x) {
for(int i=x;i<=n;i+=i&-i) t[i]++;
}
int ask(int x) {
int ans=0;
for(int i=x;i;i-=i&-i) ans+=t[i];
return ans;
}
int tot,ls[N*100],rs[N*100],siz[N*100];
void update(int &k,int l,int r,int val) {
if(!k)k=++tot;siz[k]++;
int mid=l+r>>1;
if(l==r) return;
if(val<=mid) update(ls[k],l,mid,val);
else update(rs[k],mid+1,r,val);
}
int queryx(int L,int R,int val) {
int totx=0,toty=0,ans=0;L--;
int l=1,r=n;
for(int i=L;i;i-=i&-i) x[++totx]=rt[i];
for(int i=R;i;i-=i&-i) y[++toty]=rt[i];
while(l!=r) {
int mid=l+r>>1;
if(val<=mid) {
for(int i=1;i<=totx;i++) ans-=siz[rs[x[i]]],x[i]=ls[x[i]];
for(int i=1;i<=toty;i++) ans+=siz[rs[y[i]]],y[i]=ls[y[i]];
r=mid;
}
else {
for(int i=1;i<=totx;i++) x[i]=rs[x[i]];
for(int i=1;i<=toty;i++) y[i]=rs[y[i]];
l=mid+1;
}
}
return ans;
}
int queryd(int L,int R,int val) {
int totx=0,toty=0,ans=0;L--;
int l=1,r=n;
for(int i=L;i;i-=i&-i) x[++totx]=rt[i];
for(int i=R;i;i-=i&-i) y[++toty]=rt[i];
while(l!=r) {
int mid=l+r>>1;
if(val>mid) {
for(int i=1;i<=totx;i++) ans-=siz[ls[x[i]]],x[i]=rs[x[i]];
for(int i=1;i<=toty;i++) ans+=siz[ls[y[i]]],y[i]=rs[y[i]];
l=mid+1;
}
else {
for(int i=1;i<=totx;i++) x[i]=ls[x[i]];
for(int i=1;i<=toty;i++) y[i]=ls[y[i]];
r=mid;
}
}
return ans;
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),f[i]=ask(n)-ask(a[i]),add(a[i]),ans+=f[i],pos[a[i]]=i;
memset(t,0,sizeof t);
for(int i=n;i;i--) {
g[i]=ask(a[i]);
add(a[i]);
}
int u;
for(int i=1;i<=m;i++) {
printf("%lld
",ans);
scanf("%d",&u);
u=pos[u];
ans-=(f[u]+g[u]-queryx(1,u-1,a[u])-queryd(u+1,n,a[u]));
for(int j=u;j<=n;j+=j&-j) update(rt[j],1,n,a[u]);
}
return 0;
}