洛谷 P4585 [FJOI2015]火星商店问题 题解
一、题目:
二、思路:
此题题意非常毒瘤,看完题根本不知道他在说什么。建议大家看看这个帖子。
然后讲一下这道题该怎么做。其实挺容易想到正解的。
首先考虑那些“永久性的商品”。我们发现这就是一个“可持久化Trie树”的板子题。大家可以看一下洛谷P4735 最大异或和。我也有一篇博客。
然后考虑那些在某个时间才会出现的商品。考虑用线段树对时间进行分治。那么某个时间出现商品就相当于单点修改。而查询就相当于区间询问。其实一个询问就相当于标记永久化。我们记录一个vector数组\(vec\)。\(vec\)表示从线段树的根到当前节点的路径上的询问的集合。每次访问到叶子结点时(其实就对应着单点修改),依次扫描\(vec\)中的每个询问,用该点的修改更新询问的答案即可。
三、代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
inline int read(void) {
int x = 0, f = 1; char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return f * x;
}
const int maxn = 1e5 + 5, maxm = 20;
int n, m, a[maxn], day;
int ans[maxn], sz, root[maxn];
int L[maxn << 2], R[maxn << 2];
struct Node {
int to[2];
int cnt[2];
} node[2000000];
struct Upd {
int s, v;
} upd[maxn];
struct Query {
int l, r, L, R, x, id;
} q[maxn];
struct Gch {
int l, r, x, id;
Gch() {}
Gch(int _l, int _r, int _x, int _id) : l(_l), r(_r), x(_x), id(_id) {}
};
vector<Gch>gch[maxn << 2];
vector<Gch>vec;
inline int call(int x, int i) { return (x >> i) & 1; }
inline void chkmax(int& x, int y) {
x = y > x ? y : x;
}
inline void init(void) {
root[0] = 1; sz = 1;
int p = 1;
for (int i = 18; i >= 0; --i) {
node[p].to[0] = ++sz;
node[p].cnt[0] = 1;
p = node[p].to[0];
}
}
inline int insert(int x, int fr) {
int p = fr, q = ++sz, syb = q;
for (int i = 18; i >= 0; --i) {
int now = call(x, i);
if (p) node[q] = node[p];
node[q].to[now] = ++sz;
node[q].cnt[now] = node[p].cnt[now] + 1;
p = node[p].to[now];
q = node[q].to[now];
}
return syb;
}
inline int query(int l, int r, int x) {
int p = root[l], q = root[r], res = 0;
for (int i = 18; i >= 0; --i) {
int now = call(x, i);
if (node[q].cnt[now ^ 1] - node[p].cnt[now ^ 1] > 0) {
res |= (1 << i);
p = node[p].to[now ^ 1];
q = node[q].to[now ^ 1];
}
else {
p = node[p].to[now];
q = node[q].to[now];
}
}
return res;
}
#define lson (o << 1)
#define rson (o << 1 | 1)
void build(int o, int l, int r) {
L[o] = l; R[o] = r;
if (l == r) { return; }
int mid = (l + r) >> 1;
build(lson, l, mid); build(rson, mid + 1, r);
}
void update(int o, int ql, int qr, const Gch& css) {
if (ql <= L[o] && R[o] <= qr) { gch[o].push_back(css); return; }
int mid = (L[o] + R[o]) >> 1;
if (ql <= mid) update(lson, ql, qr, css);
if (qr > mid) update(rson, ql, qr, css);
}
void dfs(int o) {
for (auto& p : gch[o]) vec.push_back(p);
if (L[o] == R[o]) {
for (auto& p : vec) {
if (p.l <= upd[L[o]].s && upd[L[o]].s <= p.r) {
chkmax(ans[p.id], p.x ^ upd[L[o]].v);
}
}
for (int i = 1; i <= (int)gch[o].size(); ++i) vec.pop_back();
return;
}
dfs(lson);
dfs(rson);
for (int i = 1; i <= (int)gch[o].size(); ++i) vec.pop_back();
}
int main() {
n = read(); m = read();
init();
for (int i = 1; i <= n; ++i) {
a[i] = read();
root[i] = insert(a[i], root[i - 1]);
}
int num = 0;
for (int i = 1; i <= m; ++i) {
int opt = read();
if (opt == 0) {
++day;
upd[day].s = read();
upd[day].v = read();
}
else if (opt == 1) {
if (i == 1) ++day;
++num;
q[num].l = read(); q[num].r = read(); q[num].x = read();
int d = read();
q[num].R = day;
q[num].L = day - d + 1;
q[num].id = num;
ans[num] = query(q[num].l - 1, q[num].r, q[num].x);
}
}
build(1, 1, day);
for (int i = 1; i <= num; ++i) {
if (q[i].L <= q[i].R)
update(1, q[i].L, q[i].R, Gch(q[i].l, q[i].r, q[i].x, q[i].id));
}
dfs(1);
for (int i = 1; i <= num; ++i)
printf("%d\n", ans[i]);
return 0;
}