Luogu P5355 [Ynoi Easy Round 2017] 由乃的玉米田 题解 [ 紫 ] [ 莫队 ] [ Bitset ] [ 根号分治 ]
考虑如何处理第四种操作,要求找到一对 \(a, b\) 满足 \(ax = b\),Bitset 是不太好做的,因此考虑根号分治:
- 对于 \(x\ge \sqrt n\) 的情况,容易发现符合条件的 \(a\) 只有 \(\sqrt n\) 个,暴力枚举 \(\bm a\) 即可。
- 对于 \(x = 1\) 的情况,显然有解。
- 对于 \(x = 0\) 的情况,显然无解。
- 对于 \(x < \sqrt n\) 的情况,此时 \(x\) 只有 \(\sqrt n\) 个,因此考虑把其他操作处理完之后最后再来处理这部分。具体而言,先枚举 \(x\) 的值,然后遍历整个序列,计算出对于每一个前缀中左端点最靠右的支配对,在此过程中处理完剩下的查询即可。
时间复杂度 \(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, SQRT = 505, MXSQRT = 317;
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;
}
}
struct Que2{
int l, r, id;
bool operator < (const Que2 & x) const{
return (r < x.r);
}
};
vector<Que2> Lines[SQRT];
int main()
{
// freopen("P5355.in", "r", stdin);
// freopen("P5355.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 if(qop == 3)
{
for(int i = 1; i * i <= qx; i++)
{
if(qx % i == 0 && bs1[i] && bs1[qx / i])
{
ans[qid] = 1;
break;
}
}
}
else
{
if(qx == 1)
{
ans[qid] = 1;
continue;
}
if(qx == 0)
{
ans[qid] = 0;
continue;
}
if(qx > MXSQRT)
{
for(int j = 1; j * qx <= MXV; j++)
{
if(bs1[j] && bs1[j * qx])
{
ans[qid] = 1;
break;
}
}
continue;
}
Lines[qx].push_back({ql, qr, qid});
}
}
for(int i = 2; i <= MXSQRT; i++)
{
sort(Lines[i].begin(), Lines[i].end());
memset(tot, -1, sizeof(tot));
int p = 1, res = -1;
for(auto qry : Lines[i])
{
int ql = qry.l, qr = qry.r, qid = qry.id;
while(p <= qr)
{
if(a[p] * i <= MXV) res = max(res, tot[a[p] * i]);
if(a[p] % i == 0) res = max(res, tot[a[p] / i]);
tot[a[p]] = p;
p++;
}
ans[qid] = (res >= ql);
}
}
for(int i = 1; i <= m; i++) cout << (ans[i] ? "yuno\n" : "yumi\n");
return 0;
}