把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【BZOJ2741】【FOTILE模拟赛】L(可持久化Trie树+分块)

点此看题面

大致题意: 给定一个序列,每次询问一段区间内最大连续异或和。

前言

好吧,看来我总是把可持久化\(Trie\)树想得太高级了,以为它什么都能搞。。。

结果做了几道题之后发现可持久化\(Trie\)树实际上似乎也就只能求一个数与一段区间内数的最大异或和,其他东西还是得另想其他方法去做。(或者还有其他用法只是我太菜不知道)

就好比这题,我一直在想怎么用纯粹的可持久化\(Trie\)树去搞,根本没往分块想。等到看到分块的标签之后,才发现其实就是一道智障题。

分块

一个显然的想法,如果我们把所有元素做一个前缀异或和,那么问题就变成了求出区间内两个数异或的最大值。

考虑我们先预处理\(ans_{i,j}\)表示从\(i\)个块的左端点\(j\)个位置的答案,显然可以\(O(\sqrt n)\)枚举每一个块,然后\(O(nlogn)\)枚举每一个位置用可持久化\(Trie\)树计算答案。

对于询问,由于完整块的答案已经预处理好了,我们只要求出左边不完整块的答案,那么\(O(\sqrt n)\)枚举不完整块中的每一个元素,然后\(O(logn)\)利用可以持久化\(Trie\)树询问,就可以了。

代码

#pragma GCC optimize(2)
#pragma GCC optimize("inline")
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 12000
#define LN 30
using namespace std;
int n,a[N+5];
class Trie//可持久化Trie树
{
	private:
		#define ST(op) O[x].S[op],O[y].S[op],v,d-1
		int Nt,Rt[N+5];struct node {int Sz,S[2];}O[(N+1)*(LN+2)+5];
		I void Ins(int& x,CI y,CI v,CI d)//插入
		{
			if(++(O[x=++Nt]=O[y]).Sz,!~d) return;Ins(ST(v>>d&1));
		}
		I int Qry(CI x,CI y,CI v,CI d)//询问
		{
			if(!~d) return 0;RI t=v>>d&1^1;
			return O[O[x].S[t]].Sz^O[O[y].S[t]].Sz?Qry(ST(t))|(1<<d):Qry(ST(t^1));
		}
	public:
		I void Ins(CI v,CI x) {Ins(Rt[v],v?Rt[v-1]:0,x,LN);}
		I int Qry(CI l,CI r,CI x) {return Qry(Rt[l-1],Rt[r],x,LN);}
}T;
class Block//分块
{
	private:
		#define SN 150
		int sz,bl[N+5],ans[SN+5][N+5];
	public:
		I void Init()//预处理答案
		{
			RI i,j;for(T.Ins(0,0),sz=sqrt(n),i=1;i<=n;++i) bl[i]=(i-1)/sz+1,T.Ins(i,a[i]);
			for(i=1;i<=bl[n];++i) for(j=(i-1)*sz+2;j<=n;++j)//枚举块以及相应位置
				ans[i][j]=max(ans[i][j-1],T.Qry((i-1)*sz+1,j-1,a[j]));//累计答案
		}
		I int Qry(CI l,CI r)//询问
		{
			RI i,t=0;if(bl[l]==bl[r]) {for(i=l;i^r;++i) t=max(t,T.Qry(i+1,r,a[i]));return t;}//如果在一个块中
			for(i=bl[l]*sz;i>=l;--i) t=max(t,T.Qry(i+1,r,a[i]));return max(t,ans[bl[l]+1][r]);//枚举不完整块的元素计算答案
		}
}B;
int main()
{
	RI Qt,i,x,y,lst=0;for(scanf("%d%d",&n,&Qt),i=1;i<=n;++i) scanf("%d",a+i),a[i]^=a[i-1];//做前缀异或和
	B.Init();W(Qt--) scanf("%d%d",&x,&y),x=(0LL+x+lst)%n+1,
		y=(0LL+y+lst)%n+1,printf("%d\n",lst=B.Qry(min(x,y)-1,max(x,y)));
	return 0;
}
posted @ 2020-05-31 17:40  TheLostWeak  阅读(139)  评论(0编辑  收藏  举报