description
戳我看题目(づ ̄3 ̄)づ╭❤~
solution
异或和最大 ——关联线性基
线性基:
- 原序列的每一个数都能由线性基里若干个数异或得到
- 线性基里若干个数的异或结果不可能为0
如果直接线段树合并线性基时间复杂度是无法接受
离线下来,考虑分治
一样的,只在左区间或右区间的分治下去处理,考虑询问跨越了中点midmidmid的
处理[l,mid][l,mid][l,mid]区间每个点的后缀线性基,[mid+1,r][mid+1,r][mid+1,r]区间每个点的前缀线性基
暴力合并线性基即可
code
#include <cstdio>
#include <cstring>
#define maxn 500005
int n, Q;
int a[maxn], ql[maxn], qr[maxn], p[maxn];
int left[maxn], right[maxn], ans[maxn];struct node {int f[20];void insert( int x ) {for( int i = 19;~ i;i -- )if( ( 1 << i ) & x ) {if( ! f[i] ) { f[i] = x; break; }else x ^= f[i];}}void clear() {memset( f, 0, sizeof( f ) );}}base[maxn];int merge( node x, node y ) { //线性基合并 int num = 0;for( int i = 19;~ i;i -- )x.insert( y.f[i] );for( int i = 19;~ i;i -- )if( ( num ^ x.f[i] ) > num ) num ^= x.f[i];return num;
}void solve( int L, int R, int l, int r ) {if( L > R || l > r ) return;if( l == r ) {for( int i = L;i <= R;i ++ )ans[p[i]] = a[l];return;}int mid = ( l + r ) >> 1, lenl = 0, lenr = 0;//暴力重构区间[l',r']的线性基base[mid].clear(); //不要忘记清空了!! base[mid].insert( a[mid] );for( int i = mid - 1;i >= l;i -- )base[i] = base[i + 1], base[i].insert( a[i] );for( int i = mid + 1;i <= r;i ++ )base[i] = base[i - 1], base[i].insert( a[i] );for( int i = L;i <= R;i ++ ) {int id = p[i];if( ql[id] <= mid ) {if( qr[id] <= mid ) //完全在左区间 递归处理 left[++ lenl] = id;elseans[id] = merge( base[ql[id]], base[qr[id]] );}else //完全在右区间 递归处理 right[++ lenr] = id;}for( int i = 1;i <= lenl;i ++ ) p[L + i - 1] = left[i];for( int i = 1;i <= lenr;i ++ ) p[L + lenl + i - 1] = right[i];solve( L, L + lenl - 1, l, mid );solve( L + lenl, L + lenl + lenr - 1, mid + 1, r );
}int main() {scanf( "%d", &n ); for( int i = 1;i <= n;i ++ )scanf( "%d", &a[i] );scanf( "%d", &Q );for( int i = 1;i <= Q;i ++ ) {scanf( "%d %d", &ql[i], &qr[i] );p[i] = i;}solve( 1, Q, 1, n );for( int i = 1;i <= Q;i ++ )printf( "%d\n", ans[i] );return 0;
}