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

Bzoj1878
Code:

#include 
#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 
#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
待填坑。

你可能感兴趣的:(莫队算法)