bzoj2741:【FOTILE模拟赛】L

题意

先分块,预处理\(f_{i,j}\)表示从第\(i\)块的开头到第\(j\)个数的答案,之后就是分块的套路了。
注意\(l,r\)加的时候会爆int。
code:

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=12010;
const int maxt=150;
int n,m,t,cnt,tot,lastans;
int a[maxn],sum[maxn],L[maxt],R[maxt],pos[maxn],root[maxn],last[maxn*40];
int f[maxt][maxn],trie[maxn*40][2];
void insert(int pre,int now,int k,int val,int id)
{
	if(k<0){last[now]=id;return;}
	int c=(val>>k)&1;
	if(pre)trie[now][c^1]=trie[pre][c^1];
	trie[now][c]=++tot;
	insert(trie[pre][c],trie[now][c],k-1,val,id);
	last[now]=max(last[trie[now][0]],last[trie[now][1]]);
}
int query(int now,int k,int val,int lim)
{
	if(k<0)return 0;
	int c=(val>>k)&1;
	if(last[trie[now][c^1]]>=lim)return (1<<k)+query(trie[now][c^1],k-1,val,lim);
	else return query(trie[now][c],k-1,val,lim);
}
inline void pre_work()
{
	root[0]=++tot,last[0]=-1;insert(0,root[0],35,0,0);
	for(int i=1;i<=n;i++)root[i]=++tot,insert(root[i-1],root[i],35,sum[i],i);
	t=(int)sqrt(n)+1;cnt=n/t;
	if(n%t)cnt++;
	for(int i=1;i<=cnt;i++)L[i]=(i-1)*t+1,R[i]=min(i*t,n);
	for(int i=1;i<=n;i++)pos[i]=(i-1)/t+1;
	for(int i=1;i<=cnt;i++)
	{
		f[i][L[i]]=0;
		for(int j=L[i]+1;j<=n;j++)f[i][j]=max(f[i][j-1],query(root[j-1],35,sum[j],L[i]));
	}
}
inline int query(int ql,int qr)
{
	int res=0;
	if(pos[ql]==pos[qr])
	{
		for(int i=ql;i<=qr;i++)res=max(res,query(root[qr],35,sum[i-1],i));
		return res;
	}
	int p=L[pos[ql]]<ql?pos[ql]+1:pos[ql];
	res=f[p][qr];
	for(int i=ql;i<=L[p];i++)res=max(res,query(root[qr],35,sum[i-1],i));
	return res;
}
signed main()
{
	//freopen("test.in","r",stdin);
	//freopen("test.out","w",stdout);
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]),sum[i]=sum[i-1]^a[i];
	pre_work();
	for(int i=1;i<=m;i++)
	{
		int l,r,x,y;scanf("%lld%lld",&x,&y);
		l=min((x+lastans)%n+1,(y+lastans)%n+1),r=max((x+lastans)%n+1,(y+lastans)%n+1);
		printf("%lld\n",lastans=query(l,r));
	}
	return 0;
}
posted @ 2019-12-10 10:51  nofind  阅读(93)  评论(0编辑  收藏  举报