[BZOJ2741][FOTILE模拟赛] L 题解
相当好的题目,虽然和我前几天出的题重了qwq。
\(lmx\) 是我们的红太阳,没有他我们就会死!!!
暴力枚举一个端点,然后用可持久化 \(01\ Trie\) 或者离线 \(Trie\)(当然这题用不了,但不强制在线的话是可以的)得到答案。时间复杂度 \(O(nm\log n)\),过不了,考虑优化。
红太阳 \(lmx\) 曾经说过:当你遇到任何一个数据结构不好处理的问题是,就可以使用分块。于是设块长为 \(k\),\(as_{i,j}\) 表示以第 \(i\) 到 \(j\times k-k+1\) 个点为左端点,以第 \(j\) 个块内的点作为右端点的区间最大异或和,\(xm_i\) 表示第 \(i\) 个块内部的点作为左右端点的区间最大异或和。
\(as_{i,j}\) 可以通过可持久化 \(Trie\ +\) 后缀最大值的方法求得,\(xm_i\) 直接枚举端点。预处理时间复杂度 \(O(\frac{n^2\log n}k)\)。
询问的时候边角用处理 \(xm_i\) 的方法处理(当然也可以预处理),整块直接调用 \(as_{l,i}\) 和 \(xm_i\) 即可。询问时间复杂度 \(O(mk\log n)\),预处理的话是 \(O(mk)\)。
容易发现 \(k=\sqrt n\) 时相对优秀,所以时间复杂度为 \(O((n+m)\sqrt n\log n)\)。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=12005,M=5e5+5,K=205;
int n,m,sm[N],rt[N],ch[M][2];
int kl,as[N][K],xm[K],la,tot;
void add(int &x,int y,int v,int id){
if(!x) x=++tot;
if(id<0) return;
int c=((v>>id)&1);
ch[x][c^1]=ch[y][c^1];
add(ch[x][c],ch[y][c],v,id-1);
}int ans(int x,int y,int v,int id){
if(id<0) return 0;
int c=1-((v>>id)&1);
if(ch[x][c]==ch[y][c])
return ans(ch[x][c^1],ch[y][c^1],v,id-1);
return (1ll<<id)+ans(ch[x][c],ch[y][c],v,id-1);
}int lt(int x){return min(x*kl,n);}
int ft(int x){return x*kl-kl+1;}
int idx(int x){return (x-1)/kl+1;}
void init(int id,int m){
int fs=rt[m],ls=rt[lt(id)+1];
for(int i=m;i;i--)
as[i][id]=ans(fs,ls,sm[i-1],35);
for(int i=m;i;i--)
as[i][id]=max(as[i][id],as[i+1][id]);
for(int i=m;i<=lt(id);i++)
xm[id]=max(xm[id],ans(rt[m-1],rt[i],sm[i],35));
}int maxn(int l,int r){
int lk=idx(l),rk=idx(r),re=0;
if(lk==rk){
for(int i=l;i<=r;i++)
re=max(re,ans(rt[l-1],rt[i],sm[i],35));
return re;
}for(int i=l;i<=lt(lk);i++)
re=max(re,ans(rt[l-1],rt[i],sm[i],35));
for(int i=lk+1;i<rk;i++) re=max({re,as[l][i],xm[i]});
for(int i=ft(rk);i<=r;i++)
re=max(re,ans(rt[l-1],rt[i],sm[i],35));
return re;
}signed main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m,kl=sqrt(n);
add(rt[0],0,0,35),add(rt[1],rt[0],0,35);
for(int i=1;i<=n;i++){
cin>>sm[i],sm[i]^=sm[i-1];
add(rt[i+1],rt[i],sm[i],35);
}for(int j=1;j<=n;j+=kl) init(idx(j),j);
while(m--){
int x,y;cin>>x>>y,x=x%n+n,y=y%n+n;
int l=min((x+la)%n+1,(y+la)%n+1);
int r=max((x+la)%n+1,(y+la)%n+1);
la=maxn(l,r),cout<<la<<"\n";
}return 0;
}