分块算法求区间众数 + 洛谷4168 P4168 [Violet]蒲公英

版权声明:本文为博主原创文章,未经博主允许也可以转载。 https://blog.csdn.net/FrankAx/article/details/82941156

分块算法求众数的主要思路就是,先预处理出任意整个块之间的众数,然后查询的时候O(1)的到L,R区间内整块的众数,然后再暴力枚举左右多余的数中是否有超过整个块中的众数。

P4168
开氧气才能过。
Code:

#include <bits/stdc++.h>
#define LL long long
using namespace std;
map<int,int>mp;
const int AX = 5e4 + 666 ;
int tot ; 
int v[AX];
int val[AX];
int block[AX];
std::vector<int> vec[AX];
int len ; 
int cnt[AX];
int f[606][606];
int n , m ;
LL read(){
	LL x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
} 
void update( int x ){
	memset( cnt , 0 , sizeof(cnt) ) ;
	int mx = 0 , idx = 0 ; 
	for( int i = (x-1)*len+1 ; i <= n ; i++ ){
		cnt[v[i]] ++ ;
		if( mx < cnt[v[i]] || ( mx == cnt[v[i]] && val[v[i]] < val[idx] ) ){
			mx = cnt[v[i]] ; idx = v[i] ;
		}
		f[x][block[i]] = idx ; 
	}
}

inline int get_num( int l ,int r ,int x){
	return upper_bound( vec[x].begin() , vec[x].end() , r ) - lower_bound( vec[x].begin() , vec[x].end() , l ) ;
}

inline int query( int l , int r ){
	int idx = f[block[l]+1][block[r]-1];
	int mx = get_num( l , r , idx ) ;
	for( int i = l ; i <= min( r , block[l] * len ) ; i++ ){
		int t = get_num( l , r , v[i] ) ;   //得到l,r区间内v[i](众数)的个数
		if( t > mx || ( t == mx && val[v[i]] < val[idx] ) ){
			mx = t ; idx = v[i] ;
		}
	}
	if( block[l] != block[r] ){
		for( int i = ( block[r] - 1 ) * len + 1 ; i <= r ; i++ ){
			int t = get_num( l , r , v[i] ) ;
			if( t > mx || ( t == mx && val[v[i]] < val[idx] ) ){
				mx = t ; idx = v[i] ;
			}
		}
	}
	return idx ; 
}

int main(){
	//scanf("%d%d",&n,&m);
	n = read();
	m = read();
	len = 200 ; 
	for( int i = 1 ; i <= n ; i++ ){
		//scanf("%d",&v[i]);
		v[i] = read();
		if( !mp[v[i]] ){
			mp[v[i]] = ++tot;
			val[tot] = v[i] ; 
		}
		v[i] = mp[v[i]];
		vec[v[i]].push_back(i) ;
	}
	for( int i = 1 ; i <= n ; i++ ) block[i] = ( i - 1 ) / len + 1 ;
		for( int i = 1 ; i <= block[n] ; i++ ){
			update(i) ; 
		}
		int l , r ; 
		int res = 0 ; 
		for( int i = 1 ; i <= m ; i++ ){
			//scanf("%d%d",&l,&r);
			l = read();
			r = read();
			l = ( l + res - 1 ) % n + 1 ;
			r = ( r + res - 1 ) % n + 1 ;
			if( l > r ) swap( l , r ) ;
			res = val[query(l,r)] ;
			printf("%d\n",res);
		}
		return 0 ;
	}

猜你喜欢

转载自blog.csdn.net/FrankAx/article/details/82941156