Luogu P3674 小清新人渣的本愿 题解 [ 紫 ] [ 莫队 ] [ Bitset ]

小清新人渣的本愿:一个经典的 Bitset 题。

注意到不强制在线,且询问的信息显然不具有结合律,所以可以尝试使用普通莫队解决这个问题。

先解决操作 \(1\),对于两数之差的限制,容易想到对值域开一个 Bitset,存区间内至少出现 \(1\) 次的数,查询的时候将这个 Bitset 右移 \(x\) 位,与自身进行按位与,只要最后的结果中至少存在 \(1\)\(1\) 则有解。

考虑操作 \(2\),问题等价于是否存在两个数 \((a, x - a)\) 都在 Bitset 中。直接做显然是不太好做的,因为 \(a\) 是不固定的。于是我们考虑先设定一个极大值 \(V\),然后开另一个 Bitset 存 \(\bm{V - i}\) 是否存在。查询的时候将第二个 Bitset 右移 \(\bm{V - x}\),和第一个 Bitset 进行按位与即可,只要最后的结果中至少存在 \(1\)\(1\) 则有解。

操作 \(3\) 是容易的,注意到值域 \(10^5\),所以可以 \(O(\sqrt V)\)枚举因数,判断是否在区间里即可。

三种操作的复杂度为 \(O(nB+n\frac{n}{B}+\frac{n^2}{\omega}+n\sqrt n)\)。其中 \(B = \sqrt n\) 最优,所以最终复杂度为 \(O(n\sqrt n + \frac{n^2}{\omega})\)

#include <bits/stdc++.h>
#define fi first
#define se second
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
#define lc(x) (tr[x].ls)
#define rc(x) (tr[x].rs)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi = pair<int, int>;
const int N = 100005, MXV = 100000;
int n, m, a[N], B, L = 1, R, tot[N], ans[N];
bitset<N> bs1, bs2;
struct Que{
    int op, l, r, x, id;
    bool operator < (const Que & t) const{
        if(l / B != t.l / B) return (l < t.l);
        if((l / B) & 1) return (r > t.r);
        return (r < t.r);
    }
}qs[N];
void add(int p)
{
    if(tot[a[p]] == 0)
    {
        bs1[a[p]] = 1;
        bs2[MXV - a[p]] = 1;
    }
    tot[a[p]]++;
}
void del(int p)
{
    tot[a[p]]--;
    if(tot[a[p]] == 0)
    {
        bs1[a[p]] = 0;
        bs2[MXV - a[p]] = 0;
    }
}
int main()
{
    //freopen("sample.in", "r", stdin);
    //freopen("sample.out", "w", stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    cin >> n >> m;
    B = sqrt(n);
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= m; i++)
    {
        int op, l, r, x;
        cin >> op >> l >> r >> x;
        qs[i] = {op, l, r, x, i};
    }
    sort(qs + 1, qs + m + 1);
    for(int i = 1; i <= m; i++)
    {
        int qop = qs[i].op, ql = qs[i].l, qr = qs[i].r, qx = qs[i].x, qid = qs[i].id;
        while(R < qr) add(++R);
        while(L > ql) add(--L);
        while(R > qr) del(R--);
        while(L < ql) del(L++);
        if(qop == 1)
            ans[qid] = (bs1 & (bs1 << qx)).any();
        else if(qop == 2)
            ans[qid] = (bs1 & (bs2 >> (MXV - qx))).any();
        else
        {
            for(int i = 1; i * i <= qx; i++)
            {
                if(qx % i == 0 && bs1[i] && bs1[qx / i])
                {
                    ans[qid] = 1;
                    break;
                }
            }
        }
    }
    for(int i = 1; i <= m; i++) cout << (ans[i] ? "hana\n" : "bi\n");
    return 0;
}
posted @ 2025-10-09 15:47  KS_Fszha  阅读(7)  评论(0)    收藏  举报