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