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