https://ac.nowcoder.com/acm/contest/5670/H
题意:
对于每一个右端点,F值不同的左端点至多为30个,所以我们只需要维护30n个 [ l , r , k = F ( l , r ) ] [l,r,k=F(l,r)] [l,r,k=F(l,r)]
建立主席树,当右端点为 r r r,枚举 [ l , r , k = F ( l , r ) ] [l,r,k=F(l,r)] [l,r,k=F(l,r)]:
最后 [ L , R ] [L,R] [L,R]的答案就是 R R R代表的主席树上,区间 [ L , R ] [L,R] [L,R]的和。
代码:
/*
* Author : Jk_Chen
* Date : 2020-07-25-10.08.08
*/
#include
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<"> "<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int N=1e5+9;
const int inf=0x3f3f3f3f;
LL read(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define rd read()
/*_________________________________________________________begin*/
int n;
int a[N];
int nxt[N][33];
int cnt;
struct node{
int l,r,k;
bool operator<(const node &A)const{
return r<A.r;
}
}e[N*30];
int cntX=0;
void work()
{
n=read();
for(int i=1;i<=n;i++)
{
a[i]=read();
}
for(int i=0;i<30;i++)nxt[0][i]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<30;j++)
{
nxt[i][j]=((1<<j)&a[i])==0?i:nxt[i-1][j];
}
}
map<int,int>mp;
for(int i=1;i<=n;i++)
{
int now=a[i],pos=i-1;
e[++cnt]={i,i,now};mp[now]=1;
while(1)
{
int minv=0;
for(int j=0;j<30;j++)
{
if(((1<<j)&now)==0)continue;
minv=max(minv,nxt[pos][j]);
}
if(minv==0)
{
break;
}
now=now&a[minv];
pos=minv;
e[++cnt]={pos,i,now};mp[now]=1;
}
}
for(auto &x:mp)x.second=++cntX;
for(int i=1;i<=cnt;i++)
{
//printf("before %d %d %d\n",e[i].l,e[i].r,e[i].k);
e[i].k=mp[e[i].k];
//printf("after %d %d %d\n",e[i].l,e[i].r,e[i].k);
}
}
int rt[N],ls[N*40*30],rs[N*40*30],cntTree,siz[N*40*30];
void insert(int last,int now,int l,int r,int p,int value){
siz[now]=siz[last]+value;
ls[now]=ls[last];
rs[now]=rs[last];//直接连原来版本的儿子
if(l==r) return ;
int mid=l+r>>1;
if(p<=mid)insert(ls[last],ls[now]=++cntTree,l,mid,p,value);//需要更新才建新点当儿子
else insert(rs[last],rs[now]=++cntTree,mid+1,r,p,value);
}
int query(int rt,int l,int r,int L,int R){
if(l>=L&&r<=R){
return siz[rt];
}
int mid=l+r>>1;
int ans=0;
if(L<=mid)ans+=query(ls[rt],l,mid,L,R);
if(R>mid)ans+=query(rs[rt],mid+1,r,L,R);
return ans;
}
int pos[N*30];
int main(){
work();
sort(e+1,e+1+cnt);
int pre=0;
rep(i,1,cnt){
int ar=e[i].r;
if(pos[e[i].k]){
if(pos[e[i].k]<e[i].l){
//printf("rt %d, pos %d -1\n",ar,pos[e[i].k]);
insert(pre,rt[ar]=++cntTree,1,n,pos[e[i].k],-1);
pre=rt[ar];
pos[e[i].k]=e[i].l;
//printf("rt %d, pos %d +1\n",ar,e[i].l);
insert(pre,rt[ar]=++cntTree,1,n,e[i].l,1);
pre=rt[ar];
pos[e[i].k]=e[i].l;
}
}
else{
//printf("rt %d, pos %d +1\n",ar,e[i].l);
insert(pre,rt[ar]=++cntTree,1,n,e[i].l,1);
pre=rt[ar];
pos[e[i].k]=e[i].l;
}
}
int q=rd;
int last=0;
while(q--){
int l=rd,r=rd;
l=(l^last)%n+1;
r=(r^last)%n+1;
if(l>r)swap(l,r);
last=query(rt[r],1,n,l,r);
printf("%d\n",last);
}
return 0;
}
/*_________________________________________________________end*/