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
- BZOJ 3295 [Cqoi2011] 动态逆序对 CDQ分治题解
- bzoj 3295: [Cqoi2011]动态逆序对 【cdq分治】
- bzoj 3295: [Cqoi2011]动态逆序对 cdq分治+树状数组
- 3295: [Cqoi2011]动态逆序对 CDQ分治
- [BZOJ3295] [Cqoi2011]动态逆序对 && CDQ分治
- 【CDQ分治】[CQOI2011][NKOJ2041]动态逆序对
- CQOI2011动态逆序对--cdq分治
- bzoj 3295: [Cqoi2011]动态逆序对 (CDQ分治+树状数组)
- BZOJ 3295 动态逆序对 CDQ分治
- bzoj 3295 动态逆序对 CDQ分治
- BZOJ 3295 动态逆序对 CDQ分治
- [BZOJ3295] [Cqoi2011]动态逆序对 (树套树)or(CDQ分治)
- CDQ分治——BZOJ3295/Luogu3157 [CQOI2011]动态逆序对
- cdq分治——P3157 [CQOI2011]动态逆序对
- [BZOJ3295][CQOI2011]动态逆序对-CDQ分治+树状数组
- BZOJ3295: [Cqoi2011]动态逆序对(CDQ分治)
- bzoj3295 [Cqoi2011]动态逆序对(CDQ分治)
- 主席树初探 & bzoj 3295: [Cqoi2011] 动态逆序对 题解
- PCI总线地址空间与系统地址空间的关系
- mybatis学习笔记二 学前准备
- PCA主成分分析
- windows 64bits+VS2015+FFmpeg实践
- GET和POST提交乱码解决方案
- BZOJ 3295 [Cqoi2011] 动态逆序对 CDQ分治题解
- C#网络编程之利用Form表单上传文件
- 区分主存、辅存
- 将jar添加到本地仓库及上传Jar到远程marven仓库
- udf--根据开始日期和结束日期获取日期范围数组
- 高德地图百度地图导航坐标转换
- Spring集成Quartz定时任务框架介绍和Cron表达式详解
- maven项目中读取.properties文件
- 解决同一activity下多个fragment 切换时重复执行onCreateView方法