#线性基#CF1100F Ivan and Burgers

题目传送门


分析

线段树上直接维护线性基是三个log的。(一定要合并)

考虑一种分治做法,在 \([l,mid]\)\((mid,r]\) 的询问分治处理,

跨过 \([mid,mid+1]\) 的维护 \([i,mid]\) 的线性基和 \([mid+1,j]\) 的线性基,

询问时合并起来,复杂度就是 \(O((n+Q)\log n\log \max\{a_i\})\)

还有一种做法就是以右端点为基准,然后尽量让线性基中的数字位置靠近右端点,插入时能替换就替换。

可以在线询问,线性基的数位置在左端点或之后就可以参与询问,这样时间复杂度是 \(O((n+Q)\log \max\{a_i\})\)


代码

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=500011; int n;
int iut(){
	int ans=0; char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=ans*10+c-48,c=getchar();
	return ans;
}
void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
struct Vector_Space{
	int re[20],tim[20];
	void BUILD(){
		memset(re,0,sizeof(re));
		memset(tim,0,sizeof(tim));
	}
	void Insert(int x,int j){
		for (int i=19;~i;--i)
		if ((x>>i)&1){
			if (!re[i]) {re[i]=x,tim[i]=j; return;}
		    else{
		    	if (tim[i]<j) swap(tim[i],j),swap(re[i],x);
		    	x^=re[i];
			}
		}
	}
	int query(int l){
		int x=0;
		for (int i=19;~i;--i)
		    if (tim[i]>=l&&(x^re[i])>x) x^=re[i];
		return x;
	}
}H[N];
int main(){
	n=iut();
	for (int i=1;i<=n;++i){
		int x=iut();
		H[i]=H[i-1],H[i].Insert(x,i);
	}
	for (int Q=iut();Q;--Q){
		int l=iut(),r=iut();
		print(H[r].query(l)),putchar(10);
	}
	return 0;
}
posted @ 2022-03-28 16:10  lemondinosaur  阅读(16)  评论(0编辑  收藏  举报