对于序列A,它的逆序对数定义为满足i
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
输出包含m行,依次为删除每个元素之前,逆序对的个数。
5 4
1
5
3
4
2
5
1
4
2
5
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
N<=100000 M<=50000
经典题…
每删一个数就把它前面比他大的 后面比他小的的贡献减去
而这些很好实现…主席树自带功能……
需要注意的是这题极其坑爹 若每次修改都按可持久化的方法插入 也就是说新建节点的话,空间方面会承受不起…因为不会访问当前节点的历史版本,所以为了节省空间,不要每次都新建……主席树的空间需求好可怕……
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int INF = 1000000010;
const int SZ = 100010;
int n,m;
int num[SZ];
namespace first{
int tmp[SZ];
int a[SZ];
LL ans = 0;
void mergesort(int l,int r)
{
if(l == r) return ;
int mid = (l + r) >> 1;
mergesort(l,mid); mergesort(mid + 1,r);
int pl = l,pr = mid + 1,p = l;
while(pl <= mid || pr <= r)
{
if(pr > r || (pl <= mid && a[pl] <= a[pr]))
tmp[p ++] = a[pl ++];
else
tmp[p ++] = a[pr ++],ans += mid - pl + 1;
}
for(int i = l;i <= r;i ++)
a[i] = tmp[i];
}
LL get_ans()
{
for(int i = 1;i <= n;i ++)
a[i] = num[i];
mergesort(1,n);
return ans;
}
}
int pos[SZ];
struct segment{
int l,r;
int cnt;
}tree[10000000];
int Tcnt = 0;
int rt[SZ];
void insert(int l,int r,int last,int &now,int x,int d)
{
if(!now) now = ++ Tcnt;
tree[now] = tree[last];
tree[now].cnt += d;
if(l == r) return ;
int mid = l + r >> 1;
if(x <= mid) insert(l,mid,tree[last].l,tree[now].l,x,d);
else insert(mid + 1,r,tree[last].r,tree[now].r,x,d);
}
void change(int pos,int x,int d)
{
for(int i = pos;i <= n;i += i & -i)
insert(1,n,rt[i],rt[i],x,d);
}
int tl,tr;
int tml[SZ],tmr[SZ];
int query_min(int l,int r,int x)
{
int L = 1,R = n;
int ans = 0;
while(L != R)
{
int mid = (L + R) >> 1;
if(mid + 1 <= x)
{
int suml = 0,sumr = 0;
for(int i = 1;i <= tl;i ++) suml += tree[tree[tml[i]].l].cnt;
for(int i = 1;i <= tr;i ++) sumr += tree[tree[tmr[i]].l].cnt;
ans += sumr - suml;
for(int i = 1;i <= tl;i ++) tml[i] = tree[tml[i]].r;
for(int i = 1;i <= tr;i ++) tmr[i] = tree[tmr[i]].r;
L = mid + 1;
}
else
{
for(int i = 1;i <= tl;i ++) tml[i] = tree[tml[i]].l;
for(int i = 1;i <= tr;i ++) tmr[i] = tree[tmr[i]].l;
R = mid;
}
}
return ans;
}
int query_max(int l,int r,int x)
{
int L = 1,R = n;
int ans = 0;
while(L != R)
{
int mid = (L + R) >> 1;
if(mid >= x)
{
int suml = 0,sumr = 0;
for(int i = 1;i <= tl;i ++) suml += tree[tree[tml[i]].r].cnt;
for(int i = 1;i <= tr;i ++) sumr += tree[tree[tmr[i]].r].cnt;
ans += sumr - suml;
for(int i = 1;i <= tl;i ++) tml[i] = tree[tml[i]].l;
for(int i = 1;i <= tr;i ++) tmr[i] = tree[tmr[i]].l;
R = mid;
}
else
{
for(int i = 1;i <= tl;i ++) tml[i] = tree[tml[i]].r;
for(int i = 1;i <= tr;i ++) tmr[i] = tree[tmr[i]].r;
L = mid + 1;
}
}
return ans;
}
int ask_min(int l,int r,int x)
{
tl = 0; tr = 0;
l --;
for(int i = l;i > 0;i -= i & -i)
tml[++ tl] = rt[i];
for(int i = r;i > 0;i -= i & -i)
tmr[++ tr] = rt[i];
return query_min(l,r,x);
}
int ask_max(int l,int r,int x)
{
tl = 0; tr = 0;
l --;
for(int i = l;i > 0;i -= i & -i)
tml[++ tl] = rt[i];
for(int i = r;i > 0;i -= i & -i)
tmr[++ tr] = rt[i];
return query_max(l,r,x);
}
void scanf(int &n)
{
n = 0;
char a = getchar();
bool flag = 0;
while(a < '0'|| a > '9') { if(a == '-') flag = 1; a = getchar(); }
while('0' <= a && a <= '9') { n = n * 10 + a - '0'; a = getchar(); }
if(flag) n = -n;
}
int main()
{
scanf(n); scanf(m);
for(int i = 1;i <= n;i ++)
{
scanf(num[i]);
pos[num[i]] = i;
change(i,num[i],1);
}
LL ans = first :: get_ans();
for(int i = 1;i <= m;i ++)
{
printf("%lld\n",ans);
int x;
scanf(x);
change(pos[x],x,-1);
int tmp1 = ask_min(pos[x] + 1,n,x),tmp2 = ask_max(1,pos[x] - 1,x);
ans -= tmp1 + tmp2;
}
return 0;
}