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

本文详细介绍了如何使用CDQ分治算法解决逆序对计数问题,特别是在元素删除过程中的应用。通过具体实例和代码解析,展示了算法的实现细节及优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

这里写图片描述

内容概要:本文详细探讨了基于樽海鞘算法(SSA)优化的极限学习机(ELM)在回归预测任务中的应用,并与传统的BP神经网络、广义回归神经网络(GRNN)以及未优化的ELM进行了性能对比。首先介绍了ELM的基本原理,即通过随机生成输入层与隐藏层之间的连接权重及阈值,仅需计算输出权重即可快速完成训练。接着阐述了SSA的工作机制,利用樽海鞘群体觅食行为优化ELM的输入权重和隐藏层阈值,从而提高模型性能。随后分别给出了BP、GRNN、ELM和SSA-ELM的具体实现代码,并通过波士顿房价数据集和其他工业数据集验证了各模型的表现。结果显示,SSA-ELM在预测精度方面显著优于其他三种方法,尽管其训练时间较长,但在实际应用中仍具有明显优势。 适合人群:对机器学习尤其是回归预测感兴趣的科研人员和技术开发者,特别是那些希望深入了解ELM及其优化方法的人。 使用场景及目标:适用于需要高效、高精度回归预测的应用场景,如金融建模、工业数据分析等。主要目标是提供一种更为有效的回归预测解决方案,尤其是在处理大规模数据集时能够保持较高的预测精度。 其他说明:文中提供了详细的代码示例和性能对比图表,帮助读者更好地理解和复现实验结果。同时提醒使用者注意SSA参数的选择对模型性能的影响,建议进行参数敏感性分析以获得最佳效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值