说在前面
之前,naive的me以为回滚莫队是和主席树类似的(支持回退嘛),然后一直没敢写过
直到写了这道题,才知道回滚莫队几乎接近暴力= =…
=w=顺便成功把这个题刷进9s,优化技巧++
题目
题目大意
给定一个长为N的数列,有Q次询问
每次询问[L,R]中,”各个数字的出现次数
∗
该数字”的最大值
输出输出格式
输入格式:
第一行两个空格分隔的整数N和Q,含义如题
接下来一行N个空格分隔的整数X1…XN,描述这个数列
接下来Q行,第i行(1<=i<=Q)有两个空格分隔整数Ai和Bi,表示第i次询问的区间为[Ai,Bi]。
输出格式:
输出Q行,第i行(1<=i<=Q)一个整数,表示第i次询问的最大重要度
解法
这个题普通莫队貌似不太好做,添加操作虽然很快,但是删除操作时间复杂度太高了…
于是回滚莫队就出现了,因为删除操作时间复杂度高,所以用添加操作去顶替
具体实现:
询问的排序方法,和普通莫队排序一样
如果询问的L和R在同一块内,直接暴力处理
如果询问的L和R不在同一块,那么对于L所在块相同的询问,排序之后R是单增的,因此右端点只会一直向右加入元素,更新答案。L所在块的那一小部分直接暴力处理
时间复杂度上限是
话说,是不是貌似普通莫队可以做的,回滚也可以做来着….
下面是自带大常数的代码
/**************************************************************
Problem: 4241
User: Izumihanako
Language: C++
Result: Accepted
Time:8816 ms
Memory:5524 kb
****************************************************************/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int N , M , a[100005] , arc[100005] ;
int Bsiz , Btot , bel[100005] , st[350] , ed[350] ;
struct Queries{
int L , R , id ;
bool operator < ( const Queries &A ) const {
return ( bel[L] < bel[A.L] ) ||
( bel[L] == bel[A.L] && R < A.R ) ;
}
}Q[100005] ;
int uninum ;
struct uniqueData{
int num , id ;
bool operator < ( const uniqueData &A ) const {
return num < A.num ;
}
}uni[100005] ;
void Unique(){
for( int i = 1 ; i <= N ; i ++ )
uni[i].num = a[i] , uni[i].id = i ;
sort( uni + 1 , uni + N + 1 ) ;
for( int i = 1 ; i <= N ; i ++ ){
if( uni[i].num != uni[i-1].num ){
uninum ++ ;
arc[uninum] = uni[i].num ;
}
a[ uni[i].id ] = uninum ;
}
}
void setBlo(){
Bsiz = sqrt( N ) ;
Btot = N / Bsiz ;
if( N % Bsiz ) Btot ++ ;
for( int i = 1 ; i <= Btot ; i ++ ){
st[i] = ed[i-1] + 1 ;
ed[i] = min( st[i] + Bsiz - 1 , N ) ;
for( int j = st[i] ; j <= ed[i] ; j ++ )
bel[j] = i ;
}
}
long long ans[100005] , now ;
int cnt[100005] , cnt2[100005] ;
void solve(){
sort( Q + 1 , Q + M + 1 ) ;
for( int i = 1 , rg , lasB = 0 ; i <= M ; i ++ ){
long long tmp = 0 ;
int L = Q[i].L , R = Q[i].R ;
if( bel[L] == bel[R] ){
for( int j = L ; j <= R ; j ++ ){
cnt2[ a[j] ] ++ ;
if( tmp < 1LL * cnt2[ a[j] ] * arc[ a[j] ] )
tmp = 1LL * cnt2[ a[j] ] * arc[ a[j] ] ;
//tmp = max( tmp , 1LL * cnt2[ a[j] ] * arc[ a[j] ] ) ;
}
ans[ Q[i].id ] = tmp ;
for( int j = L ; j <= R ; j ++ )
cnt2[ a[j] ] -- ;
} else {
if( lasB != bel[L] ){
memset( cnt , 0 , ( uninum + 1 ) * sizeof( int ) ) ;
lasB = bel[L] , now = 0 , rg = ed[ bel[L] ] ;
}
while( rg < R ){
rg ++ , cnt[ a[rg] ] ++ ;
if( now < 1LL * cnt[ a[rg] ] * arc[ a[rg] ] )
now = 1LL * cnt[ a[rg] ] * arc[ a[rg] ] ;
//now = max( now , 1LL * cnt[ a[rg] ] * arc[ a[rg] ] ) ;
}
tmp = now ;
for( int j = ed[ bel[L] ] ; j >= L ; j -- ){
cnt[ a[j] ] ++ ;
if( tmp < 1LL * cnt[ a[j] ] * arc[ a[j] ] )
tmp = 1LL * cnt[ a[j] ] * arc[ a[j] ] ;
//tmp = max( tmp , 1LL * cnt[ a[j] ] * arc[ a[j] ] ) ;
}
ans[ Q[i].id ] = tmp ;
for( int j = ed[ bel[L] ] ; j >= L ; j -- )
cnt[ a[j] ] -- ;
}
}
for( int i = 1 ; i <= M ; i ++ )
printf( "%lld\n" , ans[i] ) ;
}
inline int read_(){
int rt = 0 ;
char ch = getchar() ;
while( ch < '0' || ch > '9' ) ch = getchar() ;
while( ch >='0' && ch <='9' ) rt = rt*10 + ch - '0' , ch = getchar() ;
return rt ;
}
int main(){
register int i ;
scanf( "%d%d" , &N , &M ) ;
for( i = 1 ; i <= N ; i ++ )
a[i] = read_() ;
for( i = 1 ; i <= M ; i ++ )
Q[i].L = read_() , Q[i].R = read_() , Q[i].id = i ;
setBlo() ;
Unique() ;
solve() ;
}