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