首先我们发现或操作会使数变大,与操作会使数变小,于是可以排序后枚举分割点做到 $O(n\log n)$ 判断。

但是这样的信息并不具有可合并性之类的优良性质。

我们又发现对于 $\operatorname{popcount}$,上述性质依然成立。

但是由于 $\operatorname{popcount}$ 的级别是 $\log V$ 的,非常小,所以我们可以枚举。

小于或大于 $\operatorname{popcount}$ 分别放到或集和与集中即可。

对于等于 $\operatorname{popcount}$ 的部分,他们需要全部相等,因为分开放是不可能的,放一起就被其他的 $\operatorname{popcount}$ 情况包含了。

然后考虑全部相同的数如何放,显然如果只有一个就只能选一边放,否则就分开两边放(这样一定不劣)。

这样的信息是好合并的,只需要先枚举 $\operatorname{popcount}$,维护或集,与集,相等的数,相等的数的数量。

所以我们就可以线段树查询了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5;
const int maxm=30;
struct Value{int cnt,x,y,z;};
int n,m;
int a[maxn+5],b[maxn+5];
Value c[(maxn<<2)+5][maxm+5];
vector<int> vec;
inline int Or(int x,int y){
if(x==-1&&y==-1) return -1;
else if(x==-1) return y;
else if(y==-1) return x;
else return x|y;
}
inline int And(int x,int y){
if(x==-1&&y==-1) return -1;
else if(x==-1) return y;
else if(y==-1) return x;
else return x&y;
}
inline Value Merge(Value t1,Value t2){
Value t;
if(t1.cnt==-1||t2.cnt==-1) t.cnt=-1;
else{
if(t1.x==-1) t.cnt=t2.cnt,t.x=t2.x;
else if(t2.x==-1) t.cnt=t1.cnt,t.x=t1.x;
else if(t1.x==t2.x) t.cnt=t1.cnt+t2.cnt,t.x=t1.x;
else t.cnt=-1;
}
t.y=Or(t1.y,t2.y);
t.z=And(t1.z,t2.z);
return t;
}
inline bool Getans(Value t){
if(t.cnt==-1) return 0;
if(t.cnt==0&&t.y==t.z) return 1;
if(t.cnt==1&&(Or(t.y,t.x)==t.z||t.y==And(t.z,t.x))) return 1;
if(t.cnt>=2&&Or(t.y,t.x)==And(t.z,t.x)) return 1;
return 0;
}
void Build(int x,int L,int R){
if(L==R){
for(int p=0;p<=maxm;p++){
if(b[L]==p) c[x][p].cnt=1,c[x][p].x=a[L];
else c[x][p].cnt=0,c[x][p].x=-1;
if(b[L]<p) c[x][p].y=a[L];
else c[x][p].y=-1;
if(b[L]>p) c[x][p].z=a[L];
else c[x][p].z=-1;
}
}
else{
int mid=(R-L)/2+L;
Build(x<<1,L,mid);
Build(x<<1|1,mid+1,R);
for(int p=0;p<=maxm;p++)
c[x][p]=Merge(c[x<<1][p],c[x<<1|1][p]);
}
}
void Query(int x,int L,int R,int l,int r){
if(l<=L&&R<=r) vec.emplace_back(x);
else{
int mid=(R-L)/2+L;
if(l<=mid) Query(x<<1,L,mid,l,r);
if(mid<r) Query(x<<1|1,mid+1,R,l,r);
}
}
signed main(){
// freopen("peace3.in","r",stdin);
// freopen("peace.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
b[i]=__builtin_popcount(a[i]);
}
Build(1,1,n);
int l,r;
Value t;
for(int i=1;i<=m;i++){
scanf("%d%d",&l,&r);
vec.clear();
Query(1,1,n,l,r);
bool flg=0;
for(int p=0;p<=maxm;p++){
t=c[vec[0]][p];
for(int j=1;j<vec.size();j++)
t=Merge(t,c[vec[j]][p]);
if(Getans(t)){flg=1;break;}
}
if(flg) puts("YES");
else puts("NO");
}
return 0;
}