0%

「Luogu P3674」小清新人渣的本愿

Luogu P3674

题意

你有一个长为$n$的数列$a$,$q$个询问,有三类,每次指定一个区间$[l,r]$和一个数$x$。

  • 询问区间中是否存在两个数相加为$x$

  • 询问区间中是否存在两个数相减为$x$

  • 询问区间中是否存在两个数相乘为$x$

两个数可以在同一位置

$n,q\le10^5,0\le a_i\le10^5$


分析

直接莫队

维护正反两个值的$bitset$。

$n,q$和值域同阶,乘法$\mathcal O(\sqrt n)$枚举较小的数即可

总复杂度$\mathcal O(n(\sqrt n+\frac{n}{64}))$

跑得异常快


代码

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
#include<cstdio>
#include<algorithm>
#include<ctype.h>
#include<string.h>
#include<math.h>
#include<bitset>

using namespace std;
#define ll long long

inline char read() {
static const int IN_LEN = 1000000;
static char buf[IN_LEN], *s, *t;
return (s==t?t=(s=buf)+fread(buf,1,IN_LEN,stdin),(s==t?-1:*s++):*s++);
}
template<class T>
inline void read(T &x) {
static bool iosig;
static char c;
for (iosig=false, c=read(); !isdigit(c); c=read()) {
if (c == '-') iosig=true;
if (c == -1) return;
}
for (x=0; isdigit(c); c=read()) x=((x+(x<<2))<<1)+(c^'0');
if (iosig) x=-x;
}
const int OUT_LEN = 10000000;
char obuf[OUT_LEN], *ooh=obuf;
inline void print(char c) {
if (ooh==obuf+OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), ooh=obuf;
*ooh++=c;
}
template<class T>
inline void print(T x) {
static int buf[30], cnt;
if (x==0) print('0');
else {
if (x<0) print('-'), x=-x;
for (cnt=0; x; x/=10) buf[++cnt]=x%10+48;
while(cnt) print((char)buf[cnt--]);
}
}
inline void flush() { fwrite(obuf, 1, ooh - obuf, stdout); }

const int N = 100005;
int n, m, cnt[N], a[N], bl[N];
bool ans[N];
bitset<N> f, g;
struct query{
int opt, l, r, x, id;
inline bool operator <(const query &rhs)const{
return bl[l]==bl[rhs.l]?(r<rhs.r)^(bl[l]&1):bl[l]<bl[rhs.l];
}
}q[N];
int main() {
read(n), read(m);
for(int i=1; i<=n; ++i) read(a[i]);
for(int i=1; i<=m; ++i) read(q[i].opt), read(q[i].l), read(q[i].r), read(q[i].x), q[i].id=i;
int len=sqrt(m);
for(int i=1; i<=n; ++i) bl[i]=(i-1)/len+1;
sort(q+1, q+m+1);
int l=1, r=0;
for(int i=1; i<=m; ++i){
while(l>q[i].l) --l, f[a[l]]=g[100000-a[l]]=(++cnt[a[l]]>0);
while(r<q[i].r) ++r, f[a[r]]=g[100000-a[r]]=(++cnt[a[r]]>0);
while(l<q[i].l) f[a[l]]=g[100000-a[l]]=(--cnt[a[l]]>0), ++l;
while(r>q[i].r) f[a[r]]=g[100000-a[r]]=(--cnt[a[r]]>0), --r;
if(q[i].opt==1) ans[q[i].id]=(f&(f>>q[i].x)).any();
else if(q[i].opt==2) ans[q[i].id]=(f&(g>>(100000-q[i].x))).any();
else for(int j=1; j*j<=q[i].x; ++j)
if(q[i].x%j==0 && f[j] && f[q[i].x/j]){ ans[q[i].id]=1; break;}
}
for(int i=1; i<=m; ++i, print('\n'))
if(ans[i]) print('h'), print('a'), print('n'), print('a');
else print('b'), print('i');
return flush(), 0;
}