五彩斑斓的世界(shinku)(Ynoi2015即便看不到未来)
题目描述
给你一个序列,每次查询一段区间中长度为 1,2,...10 的极长值域连续段个数
定义值域连续段为:
把区间里面所有数排序后去重,设排序后得到的序列为 b
如果对于二元组 (l,r) 满足 b[l],b[l+1],...b[r] 中每个数为前一个数 +1
而且对于二元组 (l,r+1),(l-1,r) 均不满足,我们称 (l,r) 为一个长度为
r-l+1 的极长值域连续段
思路
查询一个区间里面长为1 -> 10的极长值域连续段的个数
这个查询是和每个数在区间中位置无关的
然后如果(l,r)是一个极长值域连续段,那不存在(l-1,r),(l,r+1)这两个值域连续段
比如这个是区间的所有值映射到值域数组上:
0 0 0 1 0 0 1 1 1 0 1 0 0 1 1 1 0 1 1 1 1 1 0 1 0
(4,4)(7,9)(11,11)(14,16)(18,22)(24,24)就是所有的极长值域连续段
每次输出区间长为1,2…k的极长值域连续段段数
部分分
A
暴力
总复杂度O( nm )
得分约为10-25
B
莫队+bitset
莫队跑出区间的值域bitset,然后用四毛子来数区间每个值域连续段即可
总复杂度O( nm/w )
得分约为35-55
C
莫队+数据结构
用数据结构维护每个值域连续段,每次莫队转移的时候可以在数据结构上二分实现
总复杂度O( nsqrtmlogn )
得分约为35-55
D
不删除莫队
维护每个极长值域连续段向左,右的最远拓展的位置
每次如果只插入的话,可以O( 1 )维护
然后套用不删除莫队即可
总复杂度O( nsqrtm )
得分约为45-55
E
莫队+位运算优化
每次查询相当于是查询一个点往前,后有多少个连续的1
然后距离超过10就无意义了
这个可以用位运算优化
单次复杂度就是O( k/w ) = O( 1 )的了
总复杂度O( nsqrtm )
得分约为45-55
做法
考虑扫描线
扫右端点,开10个树状数组表示每个左端点的每个长度的极长值域连续段的个数
维护每个值最近的出现位置(在序列上的)
扫到一个位置的时候,暴力扫左,右10个
相当于是把值在左右各10个的位置提出来,然后按照上次出现次数从大到小排序,然后一个一个插回来
这里就是左端点<=5的时候出现了一个长为2的极长值域连续段
然后左端点<=3的时候出现了一个长为3的极长值域连续段
然后左端点<=2的时候出现了一个长为7的极长值域连续段
然后左端点<=1的时候出现了一个长为10的极长值域连续段
于是相当于是:
在这个新插入的点周围的长为2的极长值域连续段出现的左端点位置是[4,5]
长为3的极长值域连续段出现的左端点位置是[3,3]
长为2的极长值域连续段出现的左端点位置是[2,2]
长为1的极长值域连续段出现的左端点位置是[1,1]
然后把原来已经加了的贡献去掉,用这个新贡献替换就可以了
每次最多产生20个新的贡献
总复杂度O( 10(n+m)logn )
代码
#include <iostream>
#include <stdio.h>
#include <vector>
#include <algorithm>
#define lowbit( i ) i & -i
#define MAXN 1000010
#define MAXK 10
#define RG 11
#define MAXD 25
using namespace std;
struct point
{
int x , y;
point( int x , int y ) : x( x ) , y( y ) {}
point() {}
} t[ MAXD ] , temp3[233];
inline bool cmp( const point & a , const point & b )
{
return a.x == b.x ? a.y > b.y : a.x > b.x;
}
vector < point > q[ MAXN ];
int n , m , cnt , a[ MAXN ] , b[ ( MAXN + MAXK ) << 1 ] , last_pos[ MAXN << 1 ] , f[ MAXN ][ MAXK ] , g[ MAXK ][ MAXN ] , res[ MAXK ] , temp1[ MAXD ] , temp2[ MAXD ];
char ans[ MAXN ][ MAXD ];
inline void modify( int x , unsigned char y , char c )
{
for( register int i = x ; i ; i ^= lowbit( i ) )
f[i][y] += c;
}
inline void query( int x , int max_pos )
{
for( register int i = 0 ; i < MAXK ; i++ ) res[i] = 0;
for( register int i = x ; i <= max_pos ; i += lowbit( i ) )
for( register unsigned char j = 0 ; j < MAXK ; j++ )
res[j] += f[i][j];
}
int pos;
inline void Modify( int x , unsigned char y , char c )
{
temp3[ pos++ ] = point( x , y );
g[y][x] += c;
}
inline void make()
{
for( register unsigned char i = 0 ; i < pos ; i++ )
if( g[ temp3[i].y ][ temp3[i].x ] )
{
modify( temp3[i].x , temp3[i].y , g[ temp3[i].y ][ temp3[i].x ] );
g[ temp3[i].y ][ temp3[i].x ] = 0;
}
pos = 0;
}
struct io //快读
{
char ibuf[1 << 25] , * s , obuf[1 << 24] , * t;
int a[24];
io() : t( obuf )
{
freopen( "shinku.in" , "rb" , stdin );
freopen( "shinku.out" , "w" , stdout );
s[ fread( s = ibuf , 1 , 1 << 25 , stdin ) ] = 0;
}
~io()
{
fwrite( obuf , 1 , t - obuf , stdout );
}
inline int read()
{
register int u = 0;
while( * s < 48 ) s++;
while( * s > 32 )
u = u * 10 + * s++ - 48;
return u;
}
inline void print( register char * u )
{
for( register unsigned char i = 0 ; i < MAXK ; i++ )
* t++ = * u++;
* t++ = '\n';
}
} ip;
#define read ip.read
#define print ip.print
int main()
{
n = read() , m = read();
for( register int i = 1 ; i <= n ; i++ ) a[i] = read();
for( register int i = 1 ; i <= m ; i++ )
{
int l = read() , r = read();
q[r].push_back( point( l , i ) );
}
for( register char i = 1 ; i <= MAXD ; i++ ) b[ ++cnt ] = 0;
for( register int i = 1 ; i <= n ; i++ ) b[ ++cnt ] = a[i] , b[ ++cnt ] = a[i] + 1;
sort( b + MAXD + 1 , b + cnt + 1 );
cnt = unique( b + MAXD + 1 , b + cnt + 1 ) - b - 1;
for( register int i = 1 ; i <= n ; i++ )
a[i] = upper_bound( b + 1 , b + cnt + 1 , a[i] ) - b - 1;
for( register int i = 1 ; i <= n ; i++ )
{
int c = 0;
for( register char j = -RG ; j <= RG ; j++ )
if( last_pos[ a[i] + j ] )
t[ c++ ] = point( last_pos[ a[i] + j ] , j + RG );
sort( t , t + c , cmp );
t[c].x = 0;
temp2[ RG ] = last_pos[ a[i] ] = i;
Modify( i , 0 , 1 );
Modify( t[0].x , 0 , -1 );
for( register int j = 0 , a , b ; j < c && t[j].y != RG ; j++ )
{
temp1[ t[j].y ] = temp2[ t[j].y ] = i;
for( a = 0 ; a < RG && temp1[ RG - a - 1 ] == i ; a++ );
for( b = 0 ; b < RG && temp1[ RG + b + 1 ] == i ; b++ );
if( a && a < RG )
Modify( t[j].x , a - 1 , -1 ) , Modify( t[j + 1].x , a - 1 , 1 );
if( b && b < RG )
Modify( t[j].x , b - 1 , -1 ) , Modify( t[j + 1].x , b - 1 , 1 );
if( a + b < MAXK )
Modify( t[j].x , a + b , 1 ) , Modify( t[j + 1].x , a + b , -1 );
}
make();
for( register vector < point > :: iterator j = q[i].begin() ; j != q[i].end() ; j++ )
{
query( j -> x , i );
for( register int k = 0 ; k < MAXK ; k++ )
ans[ j -> y ][k] = res[k] % 10 + 48;
}
}
for( register int i = 1 ; i <= m ; i++ )
print( ans[i] );
return 0;
}