本博客已停止更新!请移步至louhc.github.io

「分块系列」数列分块入门8 解题报告

数列分块入门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\n", Get( l, r, c ) );
	}
	return 0;
}

总结

分块大法好!\(^分_块\le^灵_活的暴力\le^骗_分大法\)

数列分块系列目录

数列分块入门1

数列分块入门2

数列分块入门3

数列分块入门4

数列分块入门5

数列分块入门6

数列分块入门7

数列分块入门8 <-

数列分块入门9

蒲公英

公主的朋友

posted @ 2018-12-01 21:45  louhc  阅读(564)  评论(0编辑  收藏  举报