Description
Input
Output
Sample Input
6 2
160 163 164 161 167 160
2
3
160 163 164 161 167 160
2
3
Sample Output
6
3
1
3
1
HINT
题解:首先用树状数组求出每个数到结尾的子序列有多少逆序对.加起来即是第一问答案.
对于第二问我们发现答案只会变少.而且每次减少的都是选出来的那些数往后的逆序对数.
所以我们再对所有数建一棵线段树.每次查一下选出数往后的最小值.减去对应的逆序对数,在把这个数赋成正无穷.直到查出来的数等于你选的那个数.
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 500010
#define inf 1000000001
using namespace std;
int n,m,b[N],t,x;
bool ff[N];
struct use2{int p,v;}tree[N*4],temp;
long long ans,c[N],f[N];
struct use{int v,p;}a[N];
bool cmp(use a,use b){if (a.v==b.v) return a.p<b.p;return a.v<b.v;}
int lowbit(int x){return x&(-x);}
void modify(int x){while (x<=n){c[x]+=1;x+=lowbit(x);}}
long long sum(int x){int s(0);while (x>0){s+=c[x];x-=lowbit(x);}return s;}
void insert(int k,int l,int r,int x,int w)
{
int mid=(l+r)>>1;
if (l==r&&l==x){tree[k].v=w;tree[k].p=x;return;}if (x<=mid) insert(k<<1,l,mid,x,w);
else insert(k<<1|1,mid+1,r,x,w);
if (tree[k<<1].v<tree[k<<1|1].v){tree[k].v=tree[k<<1].v;tree[k].p=tree[k<<1].p;}
else {tree[k].v=tree[k<<1|1].v;tree[k].p=tree[k<<1|1].p;}
}
use2 query(int k,int l,int r,int ll,int rr)
{
use2 a,b;a.v=inf;b.v=inf;
int mid=(l+r)>>1;
if (ll<=l&&r<=rr){return tree[k];}
if (ll<=mid) a=query(k<<1,l,mid,ll,rr);
if (mid<r) b=query(k<<1|1,mid+1,r,ll,rr);
if (a.v<b.v) return a;return b;
}
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int main()
{
n=read();m=read();
for (int i=1;i<=n;i++) {a[i].v=read();a[i].p=i;b[i]=a[i].v;}
sort(a+1,a+n+1,cmp);
for (int i=1;i<=n;i++){f[a[i].p]=sum(n)-sum(a[i].p);modify(a[i].p);}
for (int i=1;i<=n;i++)ans+=f[i];printf("%lld\n",ans);
for (int i=1;i<=n;i++) insert(1,1,n,i,b[i]);
for (int i=1;i<=m;i++)
{
x=read();
if (!ff[x])
{
temp=query(1,1,n,x,n);
while (temp.p!=x)
{
if (!ff[temp.p])ans-=f[temp.p];ff[temp.p]=true;
insert(1,1,n,temp.p,inf);
temp=query(1,1,n,x,n);
}ff[temp.p]=true;
ans-=f[temp.p];
}
printf("%lld\n",ans);
}
}