题目链接:点击查看
题目大意:给出一个长度为 n 的数列 a ,规定函数 f( l , r ) = a[ l ] & a[ l + 1 ] & ... & a[ r ] ,在规定set s( l , r ) = { f( a , b ) | l <= a <= b <= r } ,对于 q 次询问,每次询问回答 s( l , r )
题目分析:根据位运算的性质,可以知道每一位都是相互独立的,再根据与运算的性质,可以知道,当左端点或者右端点的其中一个端点在固定之后,不同的 f( l , r ) 最多有 logn 个,因为假设当前端点二进制下全部为 1 ,因为 f 函数是需要取连续的一段子数列,所以每次减少一个 1 ,最多减少 logn 次在二进制下就变为 0 了
假设数列为 a[ 1 ] , a[ 2 ] , a[ 3 ] ... a[ n - 1 ] , a[ n ] ,对于一个位置 i 来说,记录其全部的后缀,也就是:
- a[ 1 ] & a[ 2 ] & ... & a[ i - 1 ] & a[ i ]
- a[ 2 ] & a[ 3 ] & ... & a[ i - 1 ] & a[ i ]
- a[ 3 ] & a[ 4 ] & ... & a[ i - 1 ] & a[ i ]
- ......
- a[ i - 1 ] & a[ i ]
- a[ i ]
虽然一共有 i 个后缀,但根据上一段分析的性质,当固定了右端点 i 后,最多只会有 logn 个不同的数字
到此为止,剩下的就可以用主席树统计区间有多少个不同的数字的那个模板来实现了
代码:
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const int N=1e5+100;
unordered_map<int,int>mp,temp,pre;
struct Node
{
int l,r;
int sum;
}tree[N*150];
int cnt,root[N];
void init()
{
root[0]=0;
tree[0].l=tree[0].r=tree[0].sum=0;
cnt=1;
}
void update(int pos,int &k,int l,int r,int val)
{
tree[cnt++]=tree[k];
k=cnt-1;
tree[k].sum+=val;
if(l==r)
return;
int mid=l+r>>1;
if(pos<=mid)
update(pos,tree[k].l,l,mid,val);
else
update(pos,tree[k].r,mid+1,r,val);
}
int query(int rt,int l,int r,int L,int R)//[l,r]:目标区间,[L,R]:当前区间
{
if(R<l||L>r)
return 0;
if(L>=l&&R<=r)
return tree[rt].sum;
int mid=L+R>>1;
return query(tree[rt].l,l,r,L,mid)+query(tree[rt].r,l,r,mid+1,R);
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("data.in.txt","r",stdin);
// freopen("data.out.txt","w",stdout);
#endif
// ios::sync_with_stdio(false);
init();
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
root[i]=root[i-1];
int x;
scanf("%d",&x);
mp[x]=i;
temp.clear();
for(auto it=mp.begin();it!=mp.end();it++)
{
int fir=it->first,sec=it->second;
temp[x&fir]=max(temp[x&fir],sec);
}
for(auto it=temp.begin();it!=temp.end();it++)
{
int fir=it->first,sec=it->second;
if(pre[fir])
update(pre[fir],root[i],1,n,-1);
pre[fir]=sec;
update(pre[fir],root[i],1,n,1);
}
mp=temp;
}
int q,ans=0;
scanf("%d",&q);
while(q--)
{
int l,r;
scanf("%d%d",&l,&r);
l=(l^ans)%n+1;
r=(r^ans)%n+1;
if(l>r)
swap(l,r);
printf("%d\n",ans=query(root[r],l,r,1,n));
}
return 0;
}