BZOJ 3295 [Cqoi2011] 动态逆序对 CDQ分治题解

来源:互联网 发布:js attr prop 编辑:程序博客网 时间:2024/06/05 16:23

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;}

这里写图片描述

阅读全文
0 0
原创粉丝点击