Luogu 3674
题意:给你一个序列,长度为$n$,有$m$次操作,每次询问一个区间是否可以选出两个数它们的差为$x$,或者询问一个区间是否可以选出两个数它们的和为$x$,或者询问一个区间是否可以选出两个数它们的乘积为x ,这三个操作分别为操作$1,2,3$。选出的这两个数可以是同一个位置的数
无修改无强制在线,则离线即可。
给出了值域范围,那么就是让我们记录这些值
考虑如何记录。可以开桶来记录。但是这里我们并不需要知道某个数出现了几次,只需要知道有没有即可。对于这种01数组,我们可以想到bitset
设维护值域下的bitset
为$\operatorname{bs}$
对于询问一个$x=a-b$,那么就相当于bs & (bs >> x)
不为假。可以当做一个平移的感觉。
对于询问$x=a+b$,我们可以维护一个反的bitset
,然后达到将其左移后能和原来正着的bitset
有值的效果,具体可以模拟一下。
对于乘法,直接$\sqrt x$枚举即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<bitset>
#define ms(i, j) memset(i, j, sizeof i)
#define LL long long
#define db long double
#define fir first
#define sec second
#define mp make_pair
using namespace std;
namespace flyinthesky {
const int MAXN = 100000 + 5, ZY = 100000;
int n, m, blolen, bl[MAXN], a[MAXN];
int nl, nr, tax[MAXN], ans[MAXN];
bitset<ZY + 5 > bs1, bs2;
struct qry {
int l, r, ty, x, id;
bool operator < (const qry &rhs) const {
return bl[l] == bl[rhs.l] ? r < rhs.r : bl[l] < bl[rhs.l];
}
} xw[MAXN];
void inc(int pos) {
if (++tax[a[pos]] == 1) bs1[a[pos]] = bs2[ZY - a[pos]] = 1;
}
void dec(int pos) {
if (--tax[a[pos]] == 0) bs1[a[pos]] = bs2[ZY - a[pos]] = 0;
}
void clean() {
ms(ans, 0), ms(bl, 0), ms(tax, 0);
}
int solve() {
clean();
cin >> n >> m;
blolen = (int)sqrt(n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]), bl[i] = (i - 1) / blolen + 1;
for (int i = 1; i <= m; ++i) {
scanf("%d%d%d%d", &xw[i].ty, &xw[i].l, &xw[i].r, &xw[i].x);
xw[i].id = i;
}
sort(xw + 1, xw + 1 + m);
nl = 1, nr = 0;
for (int i = 1; i <= m; ++i) {
while (nl > xw[i].l) inc(nl - 1), --nl;
while (nr < xw[i].r) inc(nr + 1), ++nr;
while (nl < xw[i].l) dec(nl), ++nl;
while (nr > xw[i].r) dec(nr), --nr;
if (xw[i].ty == 1) {
if ((bs1 & (bs1 >> xw[i].x)).count()) ans[xw[i].id] = 1;
} else if (xw[i].ty == 2) {
if ((bs1 & (bs2 >> (ZY - xw[i].x))).count()) ans[xw[i].id] = 1;
//for (int i = ZY; i >= ZY - 10; --i) printf("%d", (int)bs2[i]);
} else if (xw[i].ty == 3) {
for (int j = 1; j * j <= xw[i].x; ++j) {
if (xw[i].x % j == 0) {
if (bs1[j] && bs1[xw[i].x / j]) {
ans[xw[i].id] = 1;
break;
}
}
}
}
}
for (int i = 1; i <= m; ++i)
printf("%s", ans[i] ? "hana\n" : "bi\n");
return 0;
}
}
int main() {
flyinthesky::solve();
return 0;
}
/*
5 1
1 1 2 3 4
2 3 5 7
*/