P3674 小清新人渣的本愿【莫队+ bitset】
传送门
bitset 大法好啊!!!
bitset 用法:https://blog.csdn.net/vocaloid01/article/details/82798450
解题思路:
用 bitset 的每一位代表每一个数字是否出现,s1记录每一个数x出现的位置,s2记录 maxn -x 出现的位置 (maxn可以为数值上限)
操作①:要求区间中是否能够找到满足条件的(x,y) x - y = k => x = y + k
是否存在满足条件的数,判断 s1& (s1<<k) 是否存在1 ,可以用 .any() 函数判断
操作②:要求满足条件 x + y = k => x + y - maxn = k -maxn => x + maxn - k = maxn - y
相当于判断 (s1<<(maxn- k) ) & s2 是否存在1 。
操作③:暴力枚举因子判断即可
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5;
int n, q, num[maxn + 5], pos[maxn + 5], ans[maxn + 5];
int L = 1, R = 0, cnt[maxn + 5];
bitset < maxn + 5 > s1, s2;
struct node {
int mark, l, r, k, id;
} Q[maxn + 5];
bool cmp(node a, node b) {
if(pos[a.l] == pos[b.l]) {
if(pos[a.l] & 1)
return a.r < b.r;
return a.r > b.r;
}
return a.l < b.l;
}
void add(int x) {
if(++cnt[num[x]] == 1) {
s1.set(num[x]);
s2.set(maxn - num[x]);
}
}
void del(int x) {
if(--cnt[num[x]] == 0) {
s1.reset(num[x]);
s2.reset(maxn - num[x]);
}
}
int main() {
scanf("%d %d", &n, &q);
int sz = sqrt(n);
for(int i = 1; i <= n; i++) {
scanf("%d", &num[i]);
pos[i] = i / sz;
}
for(int i = 1; i <= q; i++) {
scanf("%d %d %d %d", &Q[i].mark, &Q[i].l, &Q[i].r, &Q[i].k);
Q[i].id = i;
}
sort(Q + 1, Q + 1 + q, cmp);
for(int i = 1; i <= q; i++) {
while(Q[i].l > L)
del(L++);
while(Q[i].l < L)
add(--L);
while(Q[i].r > R)
add(++R);
while(Q[i].r < R)
del(R--);
if(Q[i].mark == 1) {
if((s1 & (s1 << Q[i].k)).any())
ans[Q[i].id] = 1;
} else if(Q[i].mark == 2) {
if(((s1 << (maxn - Q[i].k))&s2).any())
ans[Q[i].id] = 1;
} else {
for(int j = 1; j * j <= Q[i].k; j++) {
if(Q[i].k % j == 0) {
if(s1.test(j) && s1.test(Q[i].k / j)) {
ans[Q[i].id] = 1;
break;
}
}
}
}
}
for(int i = 1; i <= q; i++)
printf(ans[i] ? "hana\n" : "bi\n");
return 0;
}