zoukankan      html  css  js  c++  java
  • 「分块系列」数列分块入门9 解题报告

    数列分块入门9

    题意概括

    静态,区间求众数。

    写在前面

    还记得分块1就提到的关于块的大小有时要通过计算么??在这里就得到了体现!

    正题

    为了方便起见,我们设把数列分成K块~

    这道题很值得思考。

    先离散化~ 然后记录位置~

    我们可以考虑,对于L ~ R之间的众数只有可能是以下三种情况:

    • b[L]块中L之后的部分
    • b[R]块中R之前的部分
    • b[L] + 1块到b[R] - 1块的众数

    第三条可以预处理出。

    然后对于每次询问,直接枚举上述三种情况即可。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define MAXN 50005
    
    int n, m, T;
    int a[MAXN], b[MAXN], c[MAXN];
    int d, f[2000][2000];
    int s[MAXN];
    vector<int> p[MAXN];
    
    int Count( int l, int r, int x ){
    	return upper_bound( p[x].begin(), p[x].end(), r ) - lower_bound( p[x].begin(), p[x].end(), l );
    }
    
    int Get( int l, int r ){
    	if ( b[l] == b[r] ){
    		int ans1(0), ans2(0);
    		for ( int i = l; i <= r; ++i ){
    			int t(Count( l, r, a[i] ));
    			if ( t > ans2 ) ans1 = a[i], ans2 = t;
    			if ( t == ans2 ) ans1 = min( ans1, a[i] );
    		}
    		return ans1;
    	}
    	int ans1(f[b[l] + 1][b[r] - 1]), ans2(Count( l, r, ans1 ));
    	for ( int i = l; b[l] == b[i]; ++i ){
    		int t(Count( l, r, a[i] ));
    		if ( t == ans2 ) ans1 = min( ans1, a[i] );
    		if ( t > ans2 ) ans1 = a[i], ans2 = t;
    	}
    	for ( int i = r; b[r] == b[i]; --i ){
    		int t(Count( l, r, a[i] ));
    		if ( t == ans2 ) ans1 = min( ans1, a[i] );
    		if ( t > ans2 ) ans1 = a[i], ans2 = t;
    	}
    	return ans1;
    }
    
    int main(){
    	scanf( "%d", &n );
    	d = 0;
    	while( ( 1 << d ) <= n ) d++;
    	d--;
    	d = (int)( n / sqrt( 2 * n * d ) );
    	for ( int i = 1; i <= n; ++i ){
    		scanf( "%d", &a[i] ); c[i] = a[i]; b[i] = ( i - 1 ) / d + 1;
    	}
    	sort( c + 1, c + n + 1 );//离散化
    	m = unique( c + 1, c + n + 1 ) - c - 1;
    	for ( int i = 1; i <= n; ++i ) a[i] = lower_bound( c + 1, c + m + 1, a[i] ) - c;
    	for ( int i = 1; i <= n; ++i ) p[a[i]].push_back(i);//每个元素都记录位置
    	
    	for ( int i = 1; i <= b[n]; ++i ){
    		memset( s, 0, sizeof s );
    		int ans1(0), ans2(0);
    		for ( int j = ( i - 1 ) * d + 1; j <= n; ++j ){
    			s[a[j]]++;
    			if ( s[a[j]] == ans2 ) ans1 = min( ans1, a[j] );
    			if ( s[a[j]] > ans2 ) ans1 = a[j], ans2 = s[a[j]];
    			if ( b[j + 1] != b[j] ) f[i][b[j]] = ans1;
    		}
    	}
    	int x(0);
    	for ( int T = 1; T <= n; ++T ){
    		int l, r;
    		scanf( "%d%d", &l, &r );
    		int t(min( l, r )); r = max( l, r ); l = t;
    		printf( "%d
    ", x = c[Get( l, r )] );
    	}
    	return 0;
    }
    

    总结

    分块大法入门1~9就这么结束惹,但分块这个博大精深的暴力远远不止这些, 还有待大家去探索(((((ી(・◡・)ʃ)))))

    数列分块系列目录

    数列分块入门1

    数列分块入门2

    数列分块入门3

    数列分块入门4

    数列分块入门5

    数列分块入门6

    数列分块入门7

    数列分块入门8

    数列分块入门9 <-

    蒲公英

    公主的朋友

  • 相关阅读:
    从三道题目入门frida
    APP 抓包(应用层)
    安卓开发--探究碎片Fragment
    centos7-查询内存/硬盘等详细信息
    网页视频下载神器
    error: C++ preprocessor "/lib/cpp" fails sanity check错误解决方法
    make源文件时出现 /usr/bin/ld: cannot find -lstdc++ 错误
    安装docker后修改docker文件目录
    centos集群中各节点如何实现时间同步?
    redhat7.5 yum不能用
  • 原文地址:https://www.cnblogs.com/louhancheng/p/10051192.html
Copyright © 2011-2022 走看看