BZOJ传送门
洛谷传送门
解析:
首先我们可以通过一个线段树求出逆序对个数,然后就是乱搞的时间了。
显然每次删除一个数,需要我们查询前面比他大的数的个数和后面比他小的数的个数,这个就是裸的树套树了。这道题可以用树状数组套线段树动态开点。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define gc getchar
#define pc putchar
#define cs const
inline int getint(){
re int num;
re char c;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
return num;
}
cs int N=100005,M=10000007;
int root[N],lc[M],rc[M],siz[M],tot;
int a[N],pos[N],qa[20],qb[20],ta,tb;
int n,m;
ll ans;
inline void update(int &k,int l,int r,cs int &pos,cs int &val){
if(!k)k=++tot;siz[k]+=val;
if(l==r)return ;
int mid=(l+r)>>1;
if(pos<=mid)update(lc[k],l,mid,pos,val);
else update(rc[k],mid+1,r,pos,val);
}
#define lowbit(x) ((x)&-(x))
inline int query(int l,int r,int val,bool f){
ta=tb=0;
int res=0;
for(--l;l;l-=lowbit(l))if(root[l])qa[++ta]=root[l];
for(;r;r-=lowbit(r))if(root[r])qb[++tb]=root[r];
l=1;r=n;
while(l<r){
int mid=(l+r)>>1;
if(val<=mid){
if(!f){
for(int re i=1;i<=ta;++i)res-=siz[rc[qa[i]]];
for(int re i=1;i<=tb;++i)res+=siz[rc[qb[i]]];
}
for(int re i=1;i<=ta;++i)qa[i]=lc[qa[i]];
for(int re i=1;i<=tb;++i)qb[i]=lc[qb[i]];
r=mid;
}
else{
if(f){
for(int re i=1;i<=ta;++i)res-=siz[lc[qa[i]]];
for(int re i=1;i<=tb;++i)res+=siz[lc[qb[i]]];
}
for(int re i=1;i<=ta;++i)qa[i]=rc[qa[i]];
for(int re i=1;i<=tb;++i)qb[i]=rc[qb[i]];
l=mid+1;
}
}
return res;
}
signed main(){
n=getint();
m=getint();
for(int re i=1;i<=n;++i){
a[i]=getint();
pos[a[i]]=i;
ans+=query(1,i-1,a[i],0);
for(int re j=i;j<=n;j+=lowbit(j))update(root[j],1,n,a[i],1);
}
cout<<ans<<"\n";
for(int re i=1;i<m;++i){
int val=getint();
ans-=query(1,pos[val]-1,val,0);
ans-=query(pos[val]+1,n,val,1);
cout<<ans<<"\n";
for(int re j=pos[val];j<=n;j+=lowbit(j))update(root[j],1,n,val,-1);
}
return 0;
}