给定你一个
n
≤
1
e
5
n\leq1e5
n≤1e5的数,以及
m
≤
1
e
5
m\leq1e5
m≤1e5个询问,并且所有的数的值域都为
[
0
,
c
]
[0,c]
[0,c],每次询问给出一个值
x
x
x,然后有三种不同的询问,分别是是否区间存在两个数满足两数之差,和,积为
x
x
x。
考虑离线莫队,然后维护每个值的数量,用两个
b
i
t
s
e
t
bitset
bitset分别维护某一位
x
x
x与
1
e
5
−
x
1e5-x
1e5−x是否存在。如果存在差为
x
x
x,那么有
b
1
&
(
b
1
<
<
x
)
b1\&(b1<<x)
b1&(b1<<x)非零。如果存在和为
x
x
x,那么有
b
1
&
(
b
2
>
>
(
1
e
5
−
x
)
)
b1\&(b2>>(1e5-x))
b1&(b2>>(1e5−x))非零。对于乘积为
x
x
x,因为
x
x
x因子上界只有
x
\sqrt x
x个,所以暴力维护即可。
复杂度为
O
(
m
n
+
m
(
m
a
x
(
c
,
c
64
)
)
O(m\sqrt n+m(max(\sqrt c,\frac{c}{64}))
O(mn+m(max(c,64c))
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const ll INF=LONG_LONG_MAX;
const int N=1e5+7;
int bk[N],a[N],cnt[N];
struct Query {
int opt,l,r,x,id;
bool operator <(const Query &rhs) const {
return bk[l]==bk[rhs.l]?r<rhs.r:l<rhs.l;
}
}q[N];
int ans[N];
bitset<100005> b1,b2;
void add(int x) {
if(!cnt[x]) {
b1[x]=1;
b2[100000-x]=1;
}
cnt[x]++;
}
void del(int x) {
if(cnt[x]==1) {
b1[x]=0;
b2[100000-x]=0;
}
cnt[x]--;
}
int main() {
int n,m;
scanf("%d%d",&n,&m);
int block=sqrt(n);
for(int i=1;i<=n;i++) {
scanf("%d",&a[i]);
bk[i]=i/block;
}
for(int i=1;i<=m;i++) {
scanf("%d%d%d%d",&q[i].opt,&q[i].l,&q[i].r,&q[i].x);
q[i].id=i;
}
sort(q+1,q+1+m);
int l=1,r=0;
for(int i=1;i<=m;i++) {
while(l>q[i].l) l--,add(a[l]);
while(r<q[i].r) r++,add(a[r]);
while(l<q[i].l) del(a[l]),l++;
while(r>q[i].r) del(a[r]),r--;
int x=q[i].x;
if(q[i].opt==1) {
if((b1&(b1<<x)).any()) {
ans[q[i].id]=1;
}
}
else if(q[i].opt==2) {
if((b1&(b2>>(100000-x))).any()) {
ans[q[i].id]=1;
}
}
else if(q[i].opt==3) {
for(int j=1;j*j<=x;j++) {
if(x%j==0) {
if(cnt[j]&&cnt[x/j]) {
ans[q[i].id]=1;
break;
}
}
}
}
}
for(int i=1;i<=m;i++) {
if(ans[i]==1) puts("hana");
else puts("bi");
}
return 0;
}