题目
点这里看题目。
分析
以下设(k=lfloorlog_2(max a)
floor)。
关于异或凑数的问题自然可以用线性基处理,即如果可以插入到线性基,就说明无法凑出这个数。
于是我们就有了一个线段树或者倍增维护区间线性基的方法,时间是(O(k^2nlog_2n))。
......算了。
考虑对每一个点维护线性基(B_i),维护的是([1,i])的 " 最优 " 线性基。 " 最优 " 意味着线性基中的元素在原序列中的位置是最靠后的。
查询([l,r])的时候,我们就只能用(B_r)中位置(ge l)的元素,可以发现这样的线性基可以最多地用上里面的元素,因而是最优的。
考虑递推地构造(B)。我们从(B_{i-1})推到(B_i):将(B_{i-1})中的元素取出来,和(a_i)一起按照位置从大到小插入到(B_i)之中。可以发现这样构造的线性基可以凑出([1,i])的数,并且肯定是最优的。
根据这个构造方法我们还可以发现,查询([l,r])的时候用到的线性基的元素一定可以凑出([l,r])的数。那些位置小于(l)的元素没有被占掉说明了([l,r])中不需要它也可以凑出来。
这样递推是(O(k^2n)),还是很慢,继续优化。
(B_i)到(B_{i-1})明明只多了一个(a_i),我们却花了(O(k^2)),这显然很不划算。
如果(a_i)可以直接插入到(B_{i-1})中,我们就可以将插入(a_i)后的(B_{i-1})作为(B_i)。
否则,我们找出与插入值出现冲突的元素。如果插入值的位置比原元素更优,我们应该让插入值替换成当前位的元素,并让原元素作为插入值继续插入;否则我们就不交换,继续下一步。
可以发现这样替换得到的(B_i)肯定是最优的。由于替换出来的元素仍然会进行插入操作,并且对于(j)位上的原元素,它在(j)位以上不会有值,因此线性基可以凑出([1,i])的元素。因此我们得到了合法的最优(B_i)。时间是(O(kn))。
代码
#include <cstdio>
const int MAXN = 5e5 + 1, MAXLOG = 31;
template<typename _T>
void read( _T &x )
{
x = 0;char s = getchar();int f = 1;
while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
x *= f;
}
template<typename _T>
void write( _T x )
{
if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
if( 9 < x ){ write( x / 10 ); }
putchar( x % 10 + '0' );
}
template<typename _T>
void swapp( _T &x, _T &y )
{
_T t = x; x = y, y = t;
}
struct node
{
int val, pos;
node() {}
node( const int V, const int P ) { val = V, pos = P; }
bool operator > ( const node & b ) { return pos > b.pos; }
};
node base[MAXN][MAXLOG];
int a[MAXN];
int N;
int main()
{
read( N );
for( int i = 1 ; i <= N ; i ++ ) read( a[i] );
for( int i = 1 ; i <= N ; i ++ )
{
node cur = node( a[i], i );
for( int j = 29 ; ~ j ; j -- ) base[i][j] = base[i - 1][j];
for( int j = 29 ; ~ j ; j -- )
if( ( cur.val >> j ) & 1 )
{
if( ! base[i][j].val ) { base[i][j] = cur; break; }
if( base[i][j].pos < cur.pos ) swapp( base[i][j], cur );
cur.val ^= base[i][j].val;
}
}
int T, l, r, v;
read( T );
while( T -- )
{
read( l ), read( r ), read( v );
for( int j = 29 ; ~ j ; j -- )
if( ( v >> j ) & 1 )
{
if( ! base[r][j].val || base[r][j].pos < l ) break;
v ^= base[r][j].val;
}
puts( v ? "Budexin" : "Koyi" );
}
return 0;
}