CF979D Kuro and GCD and XOR and SUM 题解

维护 $n$ 棵 01Trie,第 $i$ 棵维护集合中 $i$ 的倍数,插入 $x$ 时,$\forall d\mid x$ 把 $x$ 插入第 $d$ 棵 01Trie,

查询 $x,k,s$ 时,在第 $k$ 棵 01Trie 中查 $\le s-x$ 的,异或 $x$ 最大的数,

维护子树最小值,贪心进入某棵子树时判一下这个子树里有没有 $\le s-x$ 的点,没有就不能进。

#include <cstdio>
#include <algorithm>
using namespace std;
struct T
{
    int v, c[2];
} R[30000050];
bool b[100050];
int n, o, p[100050];
void I(int x, int r)
{
    R[r].v = min(R[r].v, x);
    for (int i = 20, p = r; i >= 0; --i)
        if (R[p].c[x >> i & 1])
            p = R[p].c[x >> i & 1], R[p].v = min(R[p].v, x);
        else
            p = R[p].c[x >> i & 1] = ++o, R[p].v = x;
}
int Q(int x, int s, int r)
{
    if (x + R[r].v > s)
        return -1;
    int q = 0, p = r;
    for (int i = 20; i >= 0; --i)
        if (R[p].c[~x >> i & 1] && x + R[R[p].c[~x >> i & 1]].v <= s)
            p = R[p].c[~x >> i & 1];
        else
            p = R[p].c[x >> i & 1];
    return R[p].v;
}
int main()
{
    for (int i = 1; i <= 1e5; ++i)
        R[p[i] = ++o].v = 1e9;
    scanf("%d", &n);
    for (int i = 0, o, x, k, s; i < n; ++i)
    {
        scanf("%d%d", &o, &x);
        if (o & 1)
        {
            if (!b[x])
            {
                b[x] = 1;
                for (int j = 1; j * j <= x; ++j)
                    if (!(x % j))
                    {
                        I(x, p[j]);
                        if (j * j != x)
                            I(x, p[x / j]);
                    }
            }
        }
        else
            scanf("%d%d", &k, &s), printf("%d\n", x % k ? -1 : Q(x, s, p[k]));
    }
    return 0;
}
posted @ 2023-08-22 09:23  5k_sync_closer  阅读(2)  评论(0编辑  收藏  举报  来源