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;
}
posted @ 2025-10-09 21:16  KS_Fszha  阅读(7)  评论(0)    收藏  举报