离散化+树状数组+线段树
每排序一次,减少的只能是在p的右边由所有小于等于h[p]的数构成的逆序对。用线段树维护区间最小值,没个数只需访问一次,总时间复杂度O(nlogn)
#include<cstdio>
#include<algorithm>
#define N 500005
#define ll long long
#define lowbit(_i) (_i&-_i)
using namespace std;
struct seg{int l, r, minn, pos;}t[N*5];
int h[N], s[N], c[N], n, m;
pair<int,int> num[N];
const int INF = 1000000001;
int ask(int x){int ret = 0; while(x){ret+=c[x];x-=lowbit(x);} return ret;}
void add(int x){while(x<=n){c[x]++;x+=lowbit(x);}}
void make(int n)
{
h[0]=INF;
for(int i = 1; i <= n; i++)
num[i] = make_pair(h[i],i);
sort(num+1,num+1+n);
int cnt = 0;
num[0].first = -1;
for(int i = 1; i <= n; i++)
h[num[i].second] = (num[i].first == num[i-1].first ? cnt : ++cnt);
}
void merge(int x)
{
if(t[x<<1].minn < t[x<<1|1].minn)
{
t[x].minn = t[x<<1].minn;
t[x].pos = t[x<<1].pos;
}
else
{
t[x].minn = t[x<<1|1].minn;
t[x].pos = t[x<<1|1].pos;
}
}
void build(int x, int l, int r)
{
t[x].l=l;
t[x].r=r;
if(l==r)
{
t[x].minn = h[l];
t[x].pos = l;
return;
}
int mid = (l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
merge(x);
}
int query(int x, int l, int r)
{
if(l <= t[x].l && t[x].r <= r)
return t[x].pos;
int mid = (t[x].l + t[x].r)>>1, p1=0, p2=0;
if(l <= mid)p1 = query(x<<1,l,r);
if(mid < r)p2 = query(x<<1|1,l,r);
return h[p1] < h[p2] ? p1:p2;
}
void update(int x, int pos)
{
if(t[x].l == t[x].r)
{
t[x].minn = INF;
return;
}
int mid = (t[x].l + t[x].r)>>1;
if(pos<=mid)update(x<<1,pos);
else update(x<<1|1,pos);
merge(x);
}
int main()
{
ll ans = 0;
scanf("%d%d",&n,&m);
for(int i = 1; i <= n; i++)
scanf("%d",&h[i]);
make(n);
for(int i = n; i; i--)
{
s[i] = ask(h[i]-1);
ans += s[i];
add(h[i]);
}
build(1,1,n);
for(int i = 1, x; i <= m; i++)
{
printf("%lld\n",ans);
scanf("%d",&x);
int tmp = h[x];
if(tmp==INF)continue;
bool I_am_so_weak = 1;
while(I_am_so_weak)
{
int pos = query(1,x,n);
if(h[pos] > tmp)break;
h[pos] = INF;
update(1,pos);
ans -= s[pos];
}
}
printf("%lld\n",ans);
}