初见安~这里是传送门:洛谷P4585 [FJOI2015]火星商店问题
题解
听说是分治线段树套可持久化trie……蒟蒻不会分治线段树,就写了一个线段树套trie。
题意就是:n个初始为空的集合,m个操作。操作有:向某集合中加入一个整数或查询最近d次向编号在[l, r]中的集合加入的元素中,与x异或的最大值。
我们可以发现,对于询问操作有一个区间限制[l, r]和一个时间限制最近d次,再加上求最大异或值。三层限制就不能单纯用一个可持久化数据结构了,要树套树。因为是求异或最大值,我们很容易想到01trie,这一层解决了。接下来是区间和时间限制。区间我们似乎可以用线段树来框定。所以就是——开一棵线段树,区间[l, r]表示区间内的集合,线段树上每个点都开一棵01trie维护下方子节点内的信息。最后的时间限制,我们在每一个trie节点都记录一下最近一次更新的时间,若在d之前则不继续搜即可。
时间复杂度大概是。空间复杂度因为初始全空,若加入一个数值,则线段树上对应的叶子节点到根节点路径上的所有点的01trie都要加入这个数。也就是说加入一个数需要个点,空间复杂度是。
上代码——
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define maxn 40000007
using namespace std;
const int INF = 1e9;
typedef long long ll;
int read() {
int x = 0, f = 1, ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) x = (x << 1) + (x << 3) + ch - '0', ch = getchar();
return x * f;
}
int n, m, tot;
struct trie {
int t[maxn][2], mx[maxn];//因为要动态开点,所以全部放一起比较好
void add(int p, int x, int d) {
for(int i = 20; i >= 0; i--) {
register int c = x >> i & 1;
if(!t[p][c]) t[p][c] = ++tot; p = t[p][c];
mx[p] = max(mx[p], d);
}
}
int ask(int p, int x, int d, int res) {//查询最大异或值
for(int i = 20; i >= 0; i--) {
register int c = x >> i & 1;
if(t[p][c ^ 1] && mx[t[p][c ^ 1]] >= d) p = t[p][c ^ 1], res += (1 << i);
else if(mx[t[p][c]] >= d) p = t[p][c];
else return res;
}
return res;
}
}T;
void insert(int p, int l, int r, int k, int x, int d) {//加入线段树
T.add(p, x, d);//加入01trie
if(l == r) return;
register int mid = l + r >> 1;
if(k <= mid) insert(p << 1, l, mid, k, x, d);
else insert(p << 1 | 1, mid + 1, r, k, x, d);
}
int query(int p, int l, int r, int ls, int rs, int x, int d) {//线段树上区间查询
if(ls <= l && r <= rs) return T.ask(p, x, d, 0);//套进01trie求最大值
register int mid = l + r >> 1, ans = 0;
if(ls <= mid) ans = max(ans, query(p << 1, l, mid, ls, rs, x, d));
if(rs > mid) ans = max(ans, query(p << 1 | 1, mid + 1, r, ls, rs, x, d));
return ans;
}
signed main() {
n = read(), m = read(); tot = n << 2;
for(int x, i = 1; i <= n; i++) x = read(), insert(1, 1, n, i, x, INF);
register int day = 0, op, l, r, x, d;
while(m--) {
op = read();
if(!op) x = read(), d = read(), day++, insert(1, 1, n, x, d, day);
else l = read(), r = read(), x = read(), d = read(), printf("%d\n", query(1, 1, n, l, r, x, max(0, day - d + 1)));
}
return 0;
}
迎评:)
——End——