抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

传送门

设现在莫队指针l,rl,r维护的区间中不同的数组成的集合为a1,a2,a3...an{a_1,a_2,a_3...a_n}

我们维护这样一个bitset\rm bitsetss,对于aia_is[ai]=1s[a_i]=1

Query1

考虑如何实现查询xy=nx-y=n,发现x=y+nx=y+n,所以对于所有出现在aa集合中的数aia_i,查询ai+na_i+naa集合中有没有出现即可。

这个可以通过操作 (s & (s<<n)).any() ​实现,其中 any() 查询bitset\rm bitset中有没有11

Query2

考虑实现查询x+y=nx+y=n,其实本质和上面一种一样,就是化成x=y+nx=-y+n,再维护一个下标为ai-a_ibitset\rm bitsets1s1即可,但是这样做会有一个严重的问题,bitset\rm bitset下标不能为负数。

考虑给ai-a_i加上一个很大的正数NN,这里使用MAXN1MAXN-1

s1s1维护的数变为集合bi=ai+Nb_i=-a_i+N,原来的式子化成x=y+N+nNx=-y+N+n-N

查询的操作转换成查询bi+nNb_i+n-N有没有在aia_i中出现。

注意到nNn-N为负数,于是左移nNn-N转换成右移NnN-n

通过操作(s & (s1>>(N-n))).any()​实现。

Query3

这个比较简单,将xy=nxy=n转换成x=nyx=\frac{n}{y},于是O(n)O(\sqrt{n})枚举nn的所有因数即可。

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
// luogu-judger-enable-o2
//小清新莫队题
#include <bits/stdc++.h>
#define MAXN 100005
using namespace std;
inline int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=(x<<3)+(x<<1)+(ch^'0');
ch=getchar();
}
return x*f;
}
bitset<MAXN>s,s1;
int a[MAXN],cnt[MAXN],pos[MAXN];
// #define Add(x) if (cnt[x]++==0) s[x]=1,s1[MAXN-1-x]=1
// #define Del(x) if (--cnt[x]==0) s[x]=0,s1[MAXN-1-x]=0
inline void Add(int x){
if (cnt[x]++==0) s[x]=1,s1[MAXN-1-x]=1;
}
inline void Del(int x){
if (--cnt[x]==0) s[x]=0,s1[MAXN-1-x]=0;
}
struct Query{
int opt,l,r,x,id;
}q[MAXN];
inline bool operator < (const Query &a,const Query &b){
return (pos[a.l]^pos[b.l])?pos[a.l]<pos[b.l]:((pos[a.l]&1)?a.r<b.r:a.r>b.r);
}
int ans[MAXN];
int main(){
int n=read(),m=read();
int Size=(int)(sqrt(n));
for (register int i=1;i<=n;++i){
a[i]=read();
pos[i]=(i-1)/Size+1;
}
for (register int i=1;i<=m;++i){
int opt=read(),l=read(),r=read(),x=read();
q[i]=Query{opt,l,r,x,i};
}
sort(q+1,q+1+m);
int l=1,r=0;
for (register int i=1;i<=m;++i){
while (l<q[i].l) Del(a[l++]);
while (l>q[i].l) Add(a[--l]);
while (r>q[i].r) Del(a[r--]);
while (r<q[i].r) Add(a[++r]);
if (q[i].opt==1){
ans[q[i].id]=(s&(s<<(q[i].x))).any();
}
else if (q[i].opt==2){
ans[q[i].id]=(s&(s1>>(MAXN-1-q[i].x))).any();
}
else if (q[i].opt==3){
for (register int j=1;j*j<=q[i].x;++j){
if (q[i].x%j!=0) continue;
if (s[j]&&s[q[i].x/j]){
ans[q[i].id]=1;
break;
}
}
}
}
for (register int i=1;i<=m;++i){
puts(ans[i]==1?"hana":"bi");
}
}

最后提一点需要特别注意,不能乱用define\rm define,比如说

1
#define Add(x) if (cnt[a[x]]) s[a[x]]=true;

调用时

1
Add(l++)

其实相当于

1
if (cnt[a[l++]]) s[a[l++]]=true

会导致WA\rm WA

评论