bitset都没怎么用过 这题恰好能熟悉一下
这题一看就是莫队吧 然后如何看区间里面是否有两个数相减 或相加 或相乘为k
先讲相乘 因为这个最简单
我们直接暴力遍历k的因子 如果 y和k/y 都在的话 那么就可以 反正是带根号的 和莫队的复杂度一样 没什么问题
然后再说相减
对于每个数 我们用bitset记录它是否出现过 bitset s1记录 a[i] 的出现
如果区间中存在 y,q y-q=k 即 y = k+q
那么显然s1得满足 (s1&(s1<<k)) 存在任意一位为1
最后说相加 相加比较抽象 得转换一下 对于 bitset s2 我们记录 maxn-a[i]的出现 maxn是大于等于值域的一个数
如果 y+q=x
也就是 (maxn-y)-(maxn-x)=q
那么就是 s1&(s2>>(maxn-x)) 存在任意位为1
其中存在任意位为1 可以用bitset的.any()函数
另外通过样例我们知道 每个数其实可以重复选 需要注意一下
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
const int M = 1e5;
int sqn,n,m,a[N],cnt[N];
bool ans[N];
bitset<N>s1,s2;
inline int in(){
int x=0;char c=0;
while(c>'9'||c<'0') c=getchar();
while(c<='9'&&c>='0') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x;
}
struct node{
int l,r,lbk,id,op,x;
bool operator < (const node &a){
if(lbk==a.lbk) return r<a.r;
else return lbk<a.lbk;
}
}q[N];
void add(int x){
s1[a[x]]=s2[M-a[x]]=++cnt[a[x]];
}
void del(int x){
s1[a[x]]=s2[M-a[x]]=--cnt[a[x]]!=0;
}
int main(){
n=in(),m=in();
for(int i = 1; i <= n; i++) a[i]=in();
sqn=sqrt(n);
for(int i = 1; i <= m; i++){
q[i].op=in(),q[i].l=in(),q[i].r=in(),q[i].x=in();
q[i].lbk=(q[i].l-1)/sqn+1;
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) del(l++);
while(l>q[i].l) add(--l);
while(r<q[i].r) add(++r);
while(r>q[i].r) del(r--);
if(q[i].op==1){
ans[q[i].id]=(s1&(s1<<q[i].x)).any();
}else if(q[i].op==2){
ans[q[i].id]=(s1&(s2>>(M-q[i].x))).any();
}else{
for(int j = 1; j*j <= q[i].x; j++)
if(q[i].x%j==0)
if(s1[j]&&s1[q[i].x/j]) ans[q[i].id]=true;
}
}
for(int i = 1; i <= m; i++) if(ans[i]) printf("hana\n"); else printf("bi\n");
return 0;
}