传送门
题目大意:
给你
n
个数,每个数的值是
ai≤ai xor ai+1≤ai xor ai+1 xor ai+2≤⋯≤ai xor ai+1 xor ai+2⋯xor aj
有
Q
个询问,每个询问给出两个整数
题解:
令
fi
表示最大的
j
,满足
考虑第
k
个数,假设
那么只有当
枚举二进制每一位,更新
fi
。由于要强制在线,用主席树维护
fi
。
代码:
这里写代码片#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define N 400010
#define ll long long
#define M 31
char ss[30];
int Len;
inline void Print(ll x){
if(!x){
putchar(48);puts("");
return;
}
for(Len=0;x;x/=10)ss[++Len]=x%10;
while(Len)putchar(ss[Len--]+48);puts("");
}
struct Node{
ll w,t;
int s,l,r;
}c[N*80];
ll s2,s3,Ans;
int i,j,k,n,m,p,a[N],f[N],Q,Mi[2],b[N],Rt[N],Num,s1,x,y;
bool z;
inline int Min(int x,int y){
return x<y?x:y;
}
inline int Get(int x){
for(int i=M-1;i>=0;i--)
if(x&(1<<i))return i;
return -1;
}
inline void Insert(int& x,int y,int l,int r,int z,int p,int q){
x=++Num;
c[x]=c[y];
c[x].s++;c[x].w+=q;c[x].t+=p;
if(l==r)return;
int Mid=l+r>>1;
if(z<=Mid)Insert(c[x].l,c[y].l,l,Mid,z,p,q);else Insert(c[x].r,c[y].r,Mid+1,r,z,p,q);
}
inline void Query1(int x,int y,int l,int r,int L,int R){
if(!y||l>R||r<L)return;
if(l>=L&&r<=R){
s2+=c[y].w-c[x].w;
return;
}
int Mid=l+r>>1;
Query1(c[x].l,c[y].l,l,Mid,L,R);
Query1(c[x].r,c[y].r,Mid+1,r,L,R);
}
inline void Query2(int x,int y,int l,int r,int L,int R){
if(!y||l>R||r<L)return;
if(l>=L&&r<=R){
s1+=c[y].s-c[x].s;s3+=c[y].t-c[x].t;
return;
}
int Mid=l+r>>1;
Query2(c[x].l,c[y].l,l,Mid,L,R);
Query2(c[x].r,c[y].r,Mid+1,r,L,R);
}
int main(){
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]),b[i]=Get(a[i]),f[i]=n;
for(i=0;i<M;i++){
Mi[0]=Mi[1]=n+1;z=0;
for(j=n;j;j--){
f[j]=Min(f[j],Mi[z^(a[j]&(1<<i)?1:0)]-1);
if(b[j]==i)Mi[z]=j;z^=a[j]&(1<<i)?1:0;
}
}
for(i=1;i<=n;i++)Insert(Rt[i],Rt[i-1],1,n,f[i],i,f[i]-i+1);
scanf("%d",&Q);
while(Q--){
scanf("%d%d",&x,&y);
x=(Ans%n+x)%n+1;y=(Ans%n+y)%n+1;
if(x>y)swap(x,y);
s1=s2=s3=0;
Query1(Rt[x-1],Rt[y],1,n,x,y);
if(y<n)Query2(Rt[x-1],Rt[y],1,n,y+1,n);
Ans=s2-s3+1ll*(y+1)*s1;
Print(Ans);
}
return 0;
}