数列分块入门8
题意概括
区间修改,区间计数。
写在前面
感叹~ 分块真是玄之又玄|( ̄0 ̄)
正题
跟分块7类似的是,这题也运用还原。
v数组用来记录一个分块是否都为一个数,f数组来记录如果都为一个数,那么这个数是什么(实际上可以用只一个数组来记录QAQ)
查询时,对于都为一个数的块,直接加上(如果这个数是c),顺便把f改为c,不是的话暴力计数,顺便把v改为1,f改为c。
不完整的块稍微麻烦一点,如果v为1的话先还原(都变成f的值),然后再修改~
代码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100005
int n, d;
int a[MAXN], b[MAXN], f[500];
bool v[500];
int FF( int x ){//取出x位置的值
return v[b[x]] ? f[b[x]] : a[x];
}
int fun( int l, int r, int c ){//计数&修改
int ans(0);
for ( int i = l; i <= r && i <= n; ++i ) ans += FF(i) == c, a[i] = c;
return ans;
}
int Get( int l, int r, int c ){
int ans(0);
if ( b[l] == b[r] ){
if ( v[b[l]] && f[b[l]] == c ) return r - l + 1;
if ( v[b[l]] ){
fun( ( b[l] - 1 ) * d + 1, l - 1, f[b[l]] );
fun( r + 1, b[l] * d, f[b[l]] );
}
ans = fun( l, r, c );
v[b[l]] = 0;
return ans;
}
if ( v[b[l]] ) fun( ( b[l] - 1 ) * d + 1, l - 1, f[b[l]] );
ans += fun( l, b[l] * d, c );
v[b[l]] = 0;
if ( v[b[r]] ) fun( r + 1, min( b[r] * d, n ), f[b[r]] );
ans += fun( ( b[r] - 1 ) * d + 1, r, c );
v[b[r]] = 0;
for ( int i = b[l] + 1; i <= b[r] - 1; ++i ){
if ( !v[i] ){
for ( int j = ( i - 1 ) * d + 1; b[j] == i; ++j ) ans += a[j] == c, a[j] = c;
v[i] = 1; f[i] = c;
} else{
if ( f[i] == c ) ans += d;
else f[i] = c;
}
}
return ans;
}
int main(){
scanf( "%d", &n );
d = (int)sqrt(n);
for ( int i = 1; i <= n; ++i ){
scanf( "%d", &a[i] );
b[i] = ( i - 1 ) / d + 1;
}
for ( int i = 1; i <= n; ++i ){
int l, r, c;
scanf( "%d%d%d", &l ,&r, &c );
printf( "%d
", Get( l, r, c ) );
}
return 0;
}
总结
分块大法好!(^分_块le^灵_活的暴力le^骗_分大法)
数列分块系列目录
数列分块入门8 <-