题意
题解
想了一会。。
这种异或的题,一般考虑一位一位确定
考虑,如果我们确定了一个前缀,那么能选的数一定是一个区间
当我们确定下一位的时候,看一下新的区间是否有数可以符合就行了
是否符合用主席树解决
时间复杂度是
O
(
n
l
o
g
2
n
)
O(nlog^2n)
O(nlog2n)的
CODE:
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
using namespace std;
const int N=200005;
const int M=200005*22;
int S=(1<<20);
int n,m;
int s1[M],s2[M],c[M],num=0;
int rt[N];
void change (int &now,int l,int r,int x)
{
if (now==0) now=++num;
c[now]++;
if (l==r) return ;
int mid=(l+r)>>1;
if (x<=mid) change(s1[now],l,mid,x);
else change(s2[now],mid+1,r,x);
}
void Merge (int &rt,int rt1)
{
if (rt==0) {rt=rt1;return ;}
if (rt1==0) return ;
c[rt]+=c[rt1];
Merge(s1[rt],s1[rt1]);
Merge(s2[rt],s2[rt1]);
}
int calc (int now,int l,int r,int L,int R)
{
if (L>R) return 0;
L=max(L,0);R=max(R,0);
if (now==0) return 0;
if (l==L&&r==R) return c[now];
int mid=(l+r)>>1;
if (R<=mid) return calc(s1[now],l,mid,L,R);
else if (L>mid) return calc(s2[now],mid+1,r,L,R);
else return calc(s1[now],l,mid,L,mid)+calc(s2[now],mid+1,r,mid+1,R);
}
int main()
{
freopen("food1.in","r",stdin);
freopen("a.out","w",stdout);
scanf("%d%d",&n,&m);
for (int u=1;u<=n;u++)
{
int x;
scanf("%d",&x);
change(rt[u],0,S,x);
Merge(rt[u],rt[u-1]);
// if (num>=N*21)printf("%d %d\n",u,num);
}
for (int u=1;u<=m;u++)
{
int a,b,l,r;
scanf("%d%d%d%d",&a,&b,&l,&r);
//a xor (b+x[i])
int L=0,R=0;//在已经控制了的位中,答案区间是这一段都是合法的
int ans=0;
for (int u=18;u>=0;u--)
{
int x=(1<<u),xx=x-1;
if ((a&x)!=0)//这一位是1,那么我们需要一个0
{
//printf("%d %d\n",L-b,R+xx-b);
//printf("YES:%d %d %d\n",u,calc(rt[r],0,S,L-b,R+xx-b),calc(rt[l-1],0,S,L-b,R+xx-b));
if (calc(rt[r],0,S,L-b,R+xx-b)-calc(rt[l-1],0,S,L-b,R+xx-b)>0) ans=ans+x;
else {R=R+x;L=L+x;}
}
else//我们这一位需要一个1
{
// printf("%d %d\n",L-b+x,R+xx-b+x);
// printf("OZY:%d %d %d\n",u,calc(rt[r],0,S,L+x-b,R+x+xx-b),calc(rt[l-1],0,S,L+x-b,R+x+xx-b));
if (calc(rt[r],0,S,L+x-b,R+x+xx-b)-calc(rt[l-1],0,S,L+x-b,R+x+xx-b)>0)
{
L+=x;
R+=x;
ans=ans+x;
}
}
}
printf("%d\n",ans);
}
return 0;
}