Description
对于序列A,它的逆序对数定义为满足i
Input
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
Output
输出包含m行,依次为删除每个元素之前,逆序对的个数。
Sample Input
5 4
1
5
3
4
2
5
1
4
2
Sample Output
5
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
HINT
N<=100000 M<=50000
这道题是CDQ分治裸,于是我们CDQ分治愉快水之,第一维是这个数的位置,第二维是这个数的大小,第三维是时间序,其中时间序的定义为,我们把所有删除点的操作倒过来看,如果一个点第一个被删除的话,可以看成是最后一个被插入,这样一来,后面的点影响前面的点,而在计数的时候,永远都是前面的点去影响后面的点,于是我们可以得出时间序的给出方法,先把所有的需要删减的给出时间序,倒着放置,第一个被删除的就当做是第n个被插入的,把所有的删除操作进行完了之后,再把所有的其他数按照从左至右的顺序放入,时间序为1,2,3等等
cdq之前先按照时间排序
进cdq之后每次cdq时把所有的这个区间的数组分成两部分,一部分在前,一部分在后,然后讨论前面的对后面的影响,再考虑后面的对前面的影响,因为是按照t排序的,因此在这个块内一定满足左边的t是小于右边的t,因此考虑左边对右边的影响的时候,就是先把左边的东西插入,然后查询右边的(如果右边的操作时查询操作的话)已经有多少个点的值大于这个点但是坐标比这个点小,计算右边的点对左边的点的影响的情况反之
#include <cstring>
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100010;
int n, m, C[MAXN], arc[MAXN], ans[MAXN];
long long ANS;
struct data{ int x,y,t; int flag; }a[MAXN],b[MAXN];
bool cmp1( data te, data mp ) { if( te.x == mp.x ) return te.y < mp.y; return te.x < mp.x; }
bool cmp( data te, data mp ) { return te.t < mp.t; }
void add( int x, int num ) {
while( x <= n ){
C[x] += num;
x += x & (-x);
}
}
int query( int x ) {
int tmp = 0;
while( x ) {
tmp += C[x];
x -= x & (-x);
}
return tmp;
}
void CDQ( int l, int r ) {
if( l >= r ) return ;
int mid = ( l + r ) >> 1;
int cnt = 0;
for( register int i = l; i <= mid; i++ ) b[++cnt] = a[i], b[cnt].flag = 0;
for( register int i = mid + 1; i <= r; i++ ) b[++cnt] = a[i], b[cnt].flag = 1;
sort( b + 1, b + cnt + 1, cmp1);
for( register int i = 1; i <= cnt; i++ )
if( b[i].flag == 0 ) add( b[i].y, 1 );
else ans[b[i].t] += query(n) - query(b[i].y);
for( register int i = 1; i <= cnt; i++ )
if( b[i].flag == 0 ) add( b[i].y, -1 );
for( register int i = cnt; i >= 1; i-- ) {
if( b[i].flag == 0 ) add( b[i].y, 1 );
else ans[b[i].t] += query( b[i].y );
}
for( register int i = 1; i <= cnt; i++ )
if( b[i].flag == 0 ) add( b[i].y, -1 );
CDQ( l, mid );
CDQ( mid + 1, r );
}
void solve( ) {
scanf( "%d%d", &n, &m );
for( register int i = 1; i <= n; i++ ) {
a[i].x = i;
scanf( "%d", &a[i].y );
arc[a[i].y] = i;
} int tmp = n, x;
for( register int i = 1; i <= m; i++ ) {
scanf( "%d", &x );
a[arc[x]].t = tmp--;
}
for( register int i = 1; i <= n; i++ )
if( a[i].t == 0 ) a[i].t = tmp--;
sort( a + 1, a + n + 1, cmp ); CDQ( 1, n );
for( register int i = 1; i <= n; i++ ) ANS += ans[i];
for( register int i = n; i > n - m; i-- ) {
printf( "%lld\n", ANS );
ANS -= ans[i];
}
}
int main( ) {
solve( );
return 0;
}