[CF1100F]Ivan and Burgers

壹、题目

传送门 to LUOGU

贰、题解

思路和 这道题 相似。

考虑怎么去维护 \([l,r]\) 区间内的数的线性基。如果用线段树这样的数据结构去维护的话,复杂度是 \(\mathcal O(q\log n\log^2c)\) 的,显然不能通过本题。
考虑分治,还是考虑在分治过程中求出所有过中点的询问。然后考虑对于当前分治区间 \([l,r]\),求出 \([l,mid]\) 的每个后缀的线性基和 \([mid+1,r]\) 的每个前缀的线性基,然后询问的时候合并一下即可。
时间复杂度 \(\mathcal O(n\log n\log c+q\log^2c)\).

叁、代码

using namespace Elaina;

const int maxn=500000;
const int maxq=500000;
const int maxlog=20;

// Linear basis
struct basis{
	int c[maxlog+5];
	basis(){
		memset(c,0,sizeof c);
	}
	inline void clear(){
		rep(i,0,maxlog)c[i]=0;
	}
	inline void insert(int x){
		fep(i,maxlog,0)if((x>>i)&1){
			if(c[i])x^=c[i];
			else{c[i]=x;break;}
		}
	}
	inline int qmax(){
		int ret=0;
		fep(i,maxlog,0)if((ret^c[i])>ret)
			ret^=c[i];
		return ret;
	}
	inline friend basis merge(const basis lhs,const basis rhs){
		basis ret=lhs;
		fep(i,maxlog,0)if(rhs.c[i])
			ret.insert(rhs.c[i]);
		return ret;
	}
};

int a[maxn+5],n,m;

struct query{
	int l,r,id;
	query(){}
	query(const int L,const int R,const int I):l(L),r(R),id(I){}
};
query q[maxq+5],tmp[maxq+5];
int ans[maxq+5];

inline void input(){
	n=readin(1);
	rep(i,1,n)a[i]=readin(1);
	m=readin(1);
	int l,r;
	rep(i,1,m){
		l=readin(1),r=readin(1);
		q[i]=query(l,r,i);
	}
}

basis fl[maxn+5],fr[maxn+5];

inline void getl(const int l,const int r){
	fl[r+1].clear();
	fep(i,r,l){
		fl[i]=fl[i+1];
		fl[i].insert(a[i]);
	}
}

inline void getr(const int l,const int r){
	fr[l-1].clear();
	rep(i,l,r) {
		fr[i]=fr[i-1];
		fr[i].insert(a[i]);
	}
}

void solve(const int l,const int r,const int ql,const int qr){
	if(ql>qr)return;
	if(l==r){
		rep(i,ql,qr)ans[q[i].id]=a[l];
		return;
	}
	int mid=(l+r)>>1,cntl=ql-1,cntr=qr+1;
	getl(l,mid);getr(mid+1,r);
	for(int t=ql;t<=qr;++t){
		if(q[t].r<=mid)tmp[++cntl]=q[t];
		else if(mid<q[t].l)tmp[--cntr]=q[t];
		else ans[q[t].id]=merge(fl[q[t].l],fr[q[t].r]).qmax();
	}
	for(int i=ql;i<=cntl;++i)q[i]=tmp[i];
	for(int i=cntr;i<=qr;++i)q[i]=tmp[i];
	solve(l,mid,ql,cntl);
	solve(mid+1,r,cntr,qr);
}

signed main(){
	input();
	solve(1,n,1,m);
	rep(i,1,m)writc(ans[i],'\n');
	return 0;
}

肆、用到の小 \(\tt trick\)

还是考虑整体二分,但是注意使用整体二分的时候,由于需要将 "被 \(mid\) 隔开的左右两边的信息" 进行合并,所以如果信息没有可合并性,则不能使用或者需要进行一些奇怪的操作来转化.

posted @ 2021-02-17 17:15  Arextre  阅读(38)  评论(0编辑  收藏  举报