CDQ分治
把删除转变为逐个添加,于是就变成了三维偏序问题
时间,位置,大小
分两遍统计即可
# include <stdio.h>
# include <stdlib.h>
# include <iostream>
# include <algorithm>
# include <string.h>
# define IL inline
# define RG register
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
IL ll Read(){
RG char c = getchar(); RG ll x = 0, z = 1;
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + c - '0';
return x * z;
}
const int MAXN(100010);
int n, a[MAXN], id[MAXN], vis[MAXN], m, del[MAXN];
ll ans[MAXN], t[MAXN];
struct Point{
int a, b, c;
ll ans;
IL bool operator <(RG Point B) const{ return a < B.a; }
} p[MAXN], q[MAXN];
IL void Add(RG int x, RG int d){ for(; x <= n; x += x & -x) t[x] += d; }
IL int Query(RG int x){ RG int cnt = 0; for(; x; x -= x & -x) cnt += t[x]; return cnt; }
IL void CDQ(RG int l, RG int r){
if(l == r) return;
RG int mid = (l + r) >> 1, le = 0; CDQ(l, mid); CDQ(mid + 1, r);
for(RG int i = l, j = mid + 1, len = l; i <= mid || j <= r; )
if(j > r || (i <= mid && p[i].b < p[j].b)) q[len++] = p[i++];
else q[len++] = p[j++];
for(RG int i = l; i <= r; i++) p[i] = q[i];
for(RG int i = l; i <= r; i++)
if(p[i].a <= mid) Add(p[i].c, 1), le++;
else p[i].ans += le - Query(p[i].c);
for(RG int i = l; i <= r; i++)
if(p[i].a <= mid) Add(p[i].c, -1);
for(RG int i = r; i >= l; i--)
if(p[i].a <= mid) Add(p[i].c, 1);
else p[i].ans += Query(p[i].c);
for(RG int i = r; i >= l; i--)
if(p[i].a <= mid) Add(p[i].c, -1);
}
int main(RG int argc, RG char* argv[]){
n = Read(); m = Read(); RG int cnt = 0;
for(RG int i = 1; i <= n; i++) a[i] = Read(), id[a[i]] = i;
for(RG int i = 1; i <= m; i++) del[i] = Read(), vis[id[del[i]]] = 1;
for(RG int i = 1; i <= n; i++) if(!vis[i]) p[++cnt] = (Point){cnt, i, a[i]};
for(RG int i = m; i; i--) p[++cnt] = (Point){cnt, id[del[i]], del[i]};
CDQ(1, n);
sort(p + 1, p + n + 1);
for(RG int i = 1; i <= n; i++) ans[i] = ans[i - 1] + p[i].ans;
for(RG int i = n; i > n - m; i--) printf("%lld\n", ans[i]);
return 0;
}