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;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值