题目链接
思路:固定一个右端点,对于不同左端点的区间 与值,最多只有log个不同的值。
那我们枚举右端点,算出所有这样的第一次出现不同值的左端点,然后在主席树上更新一下贡献。
注意去重。可以搞一个map来辅助实现上述的操作。
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include
using namespace std;
typedef long long LL;
const int N = 1e5 + 100;
#define fi first
#define se second
#define pb push_back
#define wzh(x) cerr<<#x<<'='<
int n,a;
map<int,int>last,res,pos;
int T[N];
struct uzi{
int l,r,sum;
}t[N*400];
int cnt;
#define mid (l+r>>1)
void add(int &x,int l,int r,int z,int val){
t[++cnt]=t[x];
t[cnt].sum+=val;
x=cnt;
if(l==r)return;
if(z<=mid)add(t[x].l,l,mid,z,val);
else add(t[x].r,mid+1,r,z,val);
}
int get(int x,int l,int r,int dx,int dy){
if(l>=dx&&r<=dy) {
return t[x].sum;
}
int tmp=0;
if(dx<=mid)tmp+=get(t[x].l,l,mid,dx,dy);
if(dy>mid)tmp+=get(t[x].r,mid+1,r,dx,dy);
return tmp;
}
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) {
scanf("%d", &a);
//记录区间 和 与值
last[a]=i;
T[i]=T[i-1];
for(auto k:last){
pos[k.fi&a]=max(pos[k.fi&a],k.se);
}
for(auto k:pos){
if(res[k.fi]!=k.se){
if(res[k.fi]) {
add(T[i], 1, n, res[k.fi], -1);
}
add(T[i],1,n,k.se,1);
res[k.fi]=k.se;
}
}
last=pos;
pos.clear();
}
int la=0;
int Q;
for(scanf("%d",&Q);Q;Q--){
int l,r;
scanf("%d%d",&l,&r);
l=(l^la)%n+1;
r=(r^la)%n+1;
if(l>r)swap(l,r);
printf("%d\n",la=get(T[r],1,n,l,r));
}
return 0;
}