H-Interval
#include <bits/stdc++.h>
using namespace std;
#define maxn 100010
#define getmid int mid=(l+r)>>1
#define debug(i) cout<<"test data:"<<(i)<<'\n';
int a[maxn];
unordered_map<int,int> pre_pos;
struct Segment //线段树计算和查询区间与运算的结果
{
int sum[maxn<<2];
void push_up(int rt)
{
sum[rt] = sum[rt<<1] & sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
if(l==r){
sum[rt] = a[l];
return;
}
getmid;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
push_up(rt);
}
int query(int rt,int l,int r,int L,int R)
{
if(l>=L&&r<=R) return sum[rt];
int res = (1<<30) - 1;
getmid;
if(mid>=L) res &= query(rt<<1,l,mid,L,R);
if(mid<R) res &= query(rt<<1|1,mid+1,r,L,R);
return res;
}
}seg_tr;
struct ChairMan //主席树去重和计算答案个数
{
int sum[maxn*300],ls[maxn*300],rs[maxn*300],root[maxn],tot;
int update(int pre,int l,int r,int pos,int val)
{
int now = ++tot;
sum[now] = sum[pre];
ls[now] = ls[pre];
rs[now] = rs[pre];
sum[now] += val;
if(l==r) return now;
getmid;
if(mid>=pos) ls[now] = update(ls[now],l,mid,pos,val);
else rs[now] = update(rs[now],mid+1,r,pos,val);
return now;
}
int query(int l,int r,int L,int R,int rt)
{
if(l>=L&&r<=R) return sum[rt];
getmid;
int res = 0;
if(mid>=L) res+=query(l,mid,L,R,ls[rt]);
if(mid<R) res+=query(mid+1,r,L,R,rs[rt]);
return res;
}
}cm_tr;
int main()
{
int N,Q;
scanf("%d",&N);
for(int i=1;i<=N;i++) scanf("%d",&a[i]);
seg_tr.build(1,N,1);
cm_tr.tot = 0;
for(int i=1;i<=N;i++){
if(pre_pos[a[i]]){ //如果这个值之前出现过
cm_tr.root[i] = cm_tr.update(cm_tr.root[i-1],1,N,pre_pos[a[i]],-1); //首先删除在当前版本下的那个位置的贡献
cm_tr.root[i] = cm_tr.update(cm_tr.root[i],1,N,i,1); //在新出现的位置计算贡献(因为永远只保留最右边的那个值的贡献)
}
else cm_tr.root[i] = cm_tr.update(cm_tr.root[i-1],1,N,i,1);
pre_pos[a[i]] = i;
int p=i;
int v=a[i];
for(int j=30;j>=1;j--){ //对于每个数,它向左边做与运算得到的值的二进制1的个数必然是递减的,得到最多的不同结果就是它二进制位的个数
int l=1,r=p-1; //所以在这里循环30次(三十位),每次找出最右边第一个比F(p,i)小的数和它的位置mid。
int ret = 0;
while(l<=r){
getmid;
if(seg_tr.query(1,1,N,mid,i)<v) ret=mid,l=mid+1;
else r=mid-1;
}
if(!ret) break;
v = seg_tr.query(1,1,N,ret,i);
if(pre_pos[v]){ //同样要查看找出来的这个值有没有在之前被计算过
cm_tr.root[i] = cm_tr.update(cm_tr.root[i],1,N,pre_pos[v],-1);
}
pre_pos[v] = ret;
cm_tr.root[i] = cm_tr.update(cm_tr.root[i],1,N,ret,1);
p = ret; //继续缩小范围
}
}
scanf("%d",&Q);
int ans = 0;
while(Q--){
int ul,ur;
scanf("%d %d",&ul,&ur);
ul = (ul^ans)%N+1; ur = (ur^ans)%N+1;
if(ul>ur) swap(ul,ur);
ans = cm_tr.query(1,N,ul,ur,cm_tr.root[ur]);
printf("%d\n",ans);
}
return 0;
}