莫队小练习 Bzoj 1878 普通莫队算法 Bzoj2120 带修改莫队算法 树上莫队(待填坑)

Bzoj1878
Code:

#include <bits/stdc++.h>
#pragma comment(linker, “/STACK:1024000000,1024000000”)
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int AX = 5e4+66;
int a[AX];
int block[AX];
int cnt[1000006];
int ans ; 
struct Node{
    int l , r ;
    int id ;
    bool friend operator < ( const Node &a , const Node &b ){
        return ( ( block[a.l] == block[b.l] && a.r < b.r ) || ( block[a.l] < block[b.l] ) );
    }
}q[200006];
int res[200006];
void solve( int x , int add ){
    if( add == 1 ){
        if( !cnt[x] ) ans ++;
        cnt[x] ++;
    }else{
        cnt[x] --;
        if( !cnt[x] ) ans --;
    }
}

int main(){
    ans = 0;
    memset( cnt , 0 , sizeof(cnt) );
    int n;
    scanf("%d",&n);
    for( int i = 1 ; i <= n ; i++ ){
        scanf("%d",&a[i]);
    }
    int len = sqrt(n);
    for( int i = 1 ; i <= n ; i++ ){
        block[i] = ( i - 1 ) / len + 1 ;
    }
    int m ;
    scanf("%d",&m);
    for( int i = 1 ; i <= m ; i++ ){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id = i ;
    }
    int l = 1 , r = 0 ;
    sort( q + 1 , q + 1 + m ) ;
    for( int i = 1 ; i <= m ; i++ ){
        while( l < q[i].l ) solve( a[l++] , -1 );
        while( l > q[i].l ) solve( a[--l] , 1 );
        while( r < q[i].r ) solve( a[++r] , 1 );
        while( r > q[i].r ) solve( a[r--] , -1 );
        res[q[i].id] = ans ;
    }
    for( int i = 1 ; i <= m ; i ++ ){
        printf("%d\n",res[i]);
    }
    return 0 ;
}

带修改的莫队相对于只有查询的莫队需要多加一个时间,每块n^2/3,n^1\3块,先按照左端点所在块排序,然后按照右端点所在快,最后加了按照时间(第i个询问)排序。
设一个变量cur指向最近一次询问的时间,每次查询询问的时候,都要将时间转移到当前询问的时间。如果当前询问的时间更靠后,则顺序执行所有修改,直到达到当前询问时间;如果当前询问的时间更靠前,则还原所有多余的修改
复杂度:O(n^5/3)

Bzoj2120

Code:

#include <bits/stdc++.h>
#pragma comment(linker, “/STACK:1024000000,1024000000”)
#define INF 0x3f3f3f3f
#define LL long long
using namespace std;
const int AX = 1e4+66;
int n , m; 
int block[AX];
int len ;
int a[AX];
struct Node{
    int l , r ;
    int id ;
    int time ;
    bool friend operator < ( const Node &a , const Node &b ){
        if( block[a.l] != block[b.l] ) return a.l < b.l;
        if( block[a.r] == block[b.r] ) return a.r < b.r;
        return a.id < b.id;
    }
}q[AX];
int res[AX];
int c[AX];
int pos[AX];
int val[AX];
int cnt[1000006];
int pre[AX];
int ans , cur ;
int num_c ; 
int num_q ;
int l = 1 , r = 0 ;
void revise( int cur ){
    if( pos[cur] >= l && pos[cur] <= r ){
        cnt[a[pos[cur]]]--;
        if( !cnt[a[pos[cur]]] ) ans --;
    }
    pre[cur] = a[pos[cur]];
    a[pos[cur]] = val[cur];
    if( pos[cur] >= l && pos[cur] <= r ){
        if( !cnt[a[pos[cur]]] ) ans ++;
        cnt[a[pos[cur]]]++;
    }
}

void recover( int cur ){
    if( pos[cur] >= l && pos[cur] <= r ){
        cnt[a[pos[cur]]]--;
        if( !cnt[a[pos[cur]]] ) ans --;
    }
    a[pos[cur]] = pre[cur];
    if( pos[cur] >= l && pos[cur] <= r ){
        if( !cnt[a[pos[cur]]] ) ans ++;
        cnt[a[pos[cur]]]++;
    }
}

void change( int now ){
    while( cur < num_c && c[cur+1] <= now ) revise(++cur);
    while( cur && c[cur] > now ) recover(cur--);
}

void solve( int x , int add ){
    if( add == 1 ){
        if( !cnt[x] ) ans ++;
        cnt[x] ++;
    }else{
        cnt[x] --;
        if( !cnt[x] ) ans --;
    }
}

int main(){
    scanf("%d%d",&n,&m);
    for( int i = 1 ; i <= n ; i++ ){
        scanf("%d",&a[i]);
    }
    len = 464;  // n^2/3
    for( int i = 1 ; i <= n ; i++ ){
        block[i] = ( i - 1 ) / len + 1 ;
    }
    char op[5];
    int x , y ;
    num_q = 0 ;
    num_c = 0 ;
    ans = 0 ; cur = 0;
    memset( cnt , 0 , sizeof(cnt) );
    for( int i = 1 ; i <= m ; i++ ){
        scanf("%s%d%d",op,&x,&y);
        if( op[0] == 'Q' ){
            q[++num_q].id = num_q ;
            q[num_q].time = i ;
            q[num_q].l = x; q[num_q].r = y ;
        }else{
            c[++num_c] = i;
            pos[num_c] = x; val[num_c] = y ;
        }
    }
    sort( q + 1 , q + 1 + num_q );
    for( int i = 1 ; i <= num_q ; i++ ){
        change(q[i].time);
        while( l < q[i].l ) solve( a[l++] , -1 );
        while( l > q[i].l ) solve( a[--l] , 1 );
        while( r < q[i].r ) solve( a[++r] , 1 );
        while( r > q[i].r ) solve( a[r--] , -1 );
        res[q[i].id] = ans ;
    }
    for( int i = 1 ; i <= num_q ; i++ ){
        printf("%d\n",res[i]);
    }
    return 0 ;
}

树上莫队:讲解https://www.cnblogs.com/RabbitHu/p/MoDuiTutorial.html
待填坑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值