题意
给你
n
个数,每个数的值是
ai≤ai xor ai+1≤ai xor ai+1 xor ai+2≤⋯≤ai xor ai+1 xor ai+2⋯xor aj
有
Q
个询问,每个询问给出一个区间
题解
不错的题目。
首先要想到将限制条件简化。
如果我们能预处理出
Right[i]
,表示从
i
开始最多推到的位置,事情就变得简单了。
假设我们已经比较快的求得了
∑i=LR(min(R,Right[i])−i+1)=∑i=LRmin(R,Right[i])−(L−1+R−1)∗(R−L+1)/2
关键在 ∑Ri=Lmin(R,Right[i]) 怎么求。其实很简单,只要得到大于 R 的所有在区间中的
最后的问题:如何求 Right 呢?
考虑能超过 j 这个位置的
S(j−1) xor S(i−1)≤S(j) xor S(i−1)
考虑 S(j) 与 S(j−1) 二进制从高到低第一位不同的,显然就是在这里限制了 S(i−1) 的某一特定位置必须为特定值。
所以我们就从右往左扫,记下之前的限制 cfn[31][2] ,表示限制某一位不能是为 0/1 的最近的限制。
每次在之前的限制中得到最小的,求出 right ,然后加入限制。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define Fir first
#define Sec second
using namespace std;
typedef long long LL;
inline char gc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
char ch=gc(); int res=0,ff=1;
while(!('0'<=ch&&ch<='9')) ch=='-'?ff=-1:0, ch=gc();
while('0'<=ch&&ch<='9') res=(res<<3)+(res<<1)+ch-'0', ch=gc();
return res*ff;
}
inline void putll(LL x){ if(x/10) putll(x/10); putchar('0'+x%10); }
const int maxn=400005;
struct node{
int L,R; LL sum; int cnt;
node* ch[2];
node(int t1=0,int t2=0,LL t3=0,int t4=0,node* t5=NULL){L=t1;R=t2;sum=t3;cnt=t4;ch[0]=ch[1]=t5;}
node(node* t1):L(t1->L),R(t1->R),sum(t1->sum),cnt(t1->cnt){ch[0]=t1->ch[0];ch[1]=t1->ch[1];}
void maintain(){ sum=ch[0]->sum+ch[1]->sum; cnt=ch[0]->cnt+ch[1]->cnt; }
} nil,*null=&nil, *rt[maxn];
typedef node* P_node;
P_node Insert(P_node pre,int val){
P_node p=new node(pre);
if(p->L==val&&p->R==val){ p->sum+=val; p->cnt++; return p; }
if(val<=p->ch[0]->R) p->ch[0]=Insert(pre->ch[0],val);
else p->ch[1]=Insert(pre->ch[1],val);
p->maintain(); return p;
}
typedef pair<LL,int> Pair;
Pair merge(Pair x,Pair y){ return make_pair(x.Fir+y.Fir,x.Sec+y.Sec); }
Pair Query(P_node p1,P_node p2,int L,int R){
if(R<p1->L||p1->R<L) return make_pair(0,0);
if(L<=p1->L&&p1->R<=R) return make_pair(p1->sum-p2->sum,p1->cnt-p2->cnt);
return merge(Query(p1->ch[0],p2->ch[0],L,R),Query(p1->ch[1],p2->ch[1],L,R));
}
P_node build(int L,int R){
P_node p=new node(L,R,0,0,null);
if(L==R) return p;
int mid=(L+R)>>1;
p->ch[0]=build(L,mid); p->ch[1]=build(mid+1,R);
p->maintain(); return p;
}
int n,Q,_t,s[maxn],Right[maxn],cfn[33][2];
LL ans;
int main(){
null->ch[0]=null->ch[1]=null;
n=getint(); _t=getint();
for(int i=1;i<=n;i++) s[i]=(getint()^s[i-1]);
memset(cfn,63,sizeof(cfn));
for(int i=n;i>=1;i--){
Right[i]=n; for(int j=0;j<=31;j++) Right[i]=min(Right[i],cfn[j][(s[i-1]>>j)&1]-1);
for(int k=31;k>=0;k--) if(((s[i]>>k)&1)!=((s[i-1]>>k)&1)){
cfn[k][(s[i]>>k)&1]=min(cfn[k][(s[i]>>k)&1],i);
break;
}
}
rt[0]=build(1,n); for(int i=1;i<=n;i++) rt[i]=Insert(rt[i-1],Right[i]);
Q=getint();
while(Q--){
int L=getint(),R=getint();
L=(L+ans*_t)%n+1; R=(R+ans*_t)%n+1; if(L>R) swap(L,R);
ans=Query(rt[R],rt[L-1],1,n).Fir; Pair t=Query(rt[R],rt[L-1],R,n);
ans=ans-t.Fir+(LL)t.Sec*R; ans=ans-(LL)(R-L+1)*(L+R-2)/2;
putll(ans); putchar('\n');
}
return 0;
}