UVa12345 Dynamic len

题目大意

有n个数编号从0→n-1,两种操作:
Q L R:询问编号为L→R-1的数中共有多少种不同的数
M X Y:将编号为X的数改为Y
共有m个操作

Data Constraint
n,m50000

题解

解法一:树套树

f[i] 表示 i 前面第一个位置,使得 a[f[i]]=a[i]
问题转化为求区间 [L,R] 内有多少个数 f[i]<L
可以用树套树维护。

解法二:带修莫队

一个三维的莫队算法,按 n23 来分块。记 (L,R,Time) 表示一个询问区间 [L,R] 发生在第 Time 次修改之后。 Pos[i] 表示位置 i 分块之后的编号。
然后以 Pos[L] 为第一关键字, Pos[R] 为第二关键字, Time 为第三关键字排序。
每次当已完成的修改比当前询问所需修改要少时,就把完成操作。反之,就撤销操作(记录上一个值)。
时间复杂度: O(n53)

SRC

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std ;

#define N 50000 + 10
#define M 1000000 + 10
struct Query {
    int l , r , occ , h ;
} Q[N] ;
struct Modify {
    int w , v , last ;
} C[N] ;

bool Flag[M] ;
int Tax[M] , Ans[N] ;
int a[N] , Pos[N] , Last[N] ;
int L = 1 , R = 0 , Cnt = 0 ;
int n , m , Size ;
int tot1 , tot2 ;
int Count ;

bool cmp( Query a , Query b ) {
    if ( Pos[a.l] < Pos[b.l] ) return 1 ;
    if ( Pos[a.l] == Pos[b.l] && Pos[a.r] < Pos[b.r] ) return 1 ;
    if ( Pos[a.l] == Pos[b.l] && Pos[a.r] == Pos[b.r] && a.occ < b.occ ) return 1 ;
    return 0 ;
}

void Del( int w ) {
    Tax[a[w]] -- ;
    if ( Tax[a[w]] == 0 ) Count -- ;
    Flag[w] = 0 ;
}

void Add( int w ) {
    Tax[a[w]] ++ ;
    if ( Tax[a[w]] == 1 ) Count ++ ;
    Flag[w] = 1 ;
}

void Insert( int w ) {
    if ( Flag[w] ) Del(w) ;
    else Add(w) ;
}

void Change( int w , int v ) {
    if ( Flag[w] ) {
        Del(w) ;
        a[w] = v ;
        Add(w) ;
    } else a[w] = v ;
}

void Update( Query Q ) {
    if ( L < Q.l ) for (int j = L ; j < Q.l ; j ++ ) Insert(j) ;
    else for (int j = Q.l ; j < L ; j ++ ) Insert(j) ;
    if ( R < Q.r ) for (int j = R + 1 ; j <= Q.r ; j ++ ) Insert(j) ;
    else for (int j = Q.r + 1 ; j <= R ; j ++ ) Insert(j) ;
    L = Q.l , R = Q.r ;
    Cnt = Q.occ ;
    Ans[Q.h] = Count ;
}

int main() {
    freopen( "len.in" , "r" , stdin ) ;
    freopen( "len.out" , "w" , stdout ) ;
    scanf( "%d%d" , &n , &m ) ;
    Size = (int)pow( n , 2.0 / 3.0 ) + 1 ;
    for (int i = 1 ; i <= n ; i ++ ) {
        scanf( "%d" , &a[i] ) ;
        Last[i] = a[i] ;
        Pos[i] = (i + 1) / Size ;
    }
    for (int i = 1 ; i <= m ; i ++ ) {
        char op ;
        scanf( "\n%c" , &op ) ;
        if ( op == 'M' ) {
            tot2 ++ ;
            scanf( "%d%d" , &C[tot2].w , &C[tot2].v ) ;
            C[tot2].w ++ ;
            C[tot2].last = Last[C[tot2].w] ;
            Last[C[tot2].w] = C[tot2].v ;
        } else {
            tot1 ++ ;
            scanf( "%d%d" , &Q[tot1].l , &Q[tot1].r ) ;
            Q[tot1].l ++ ;
            Q[tot1].h = tot1 ;
            Q[tot1].occ = tot2 ;
        }
    }
    sort( Q + 1 , Q + tot1 + 1 , cmp ) ;
    for (int i = 1 ; i <= tot1 ; i ++ ) {
        if ( Cnt < Q[i].occ ) {
            for (int j = Cnt + 1 ; j <= Q[i].occ ; j ++ )
                Change( C[j].w , C[j].v ) ;
        } else {
            for (int j = Cnt ; j > Q[i].occ ; j -- )
                Change( C[j].w , C[j].last ) ;
        }
        Update( Q[i] ) ;
    }
    for (int i = 1 ; i <= tot1 ; i ++ ) printf( "%d\n" , Ans[i] ) ;
    return 0 ;
}

以上.

你可能感兴趣的:(uva)