我把大家的疑惑解答写在中间了hh
#include <iostream>
#include <cstdio>
using namespace std;
const int N = 6e5 + 10, M = 25 * N;
int s[N];
int tr[M][2], max_id[M];
int root[N], idx;
void insert(int k, int p, int q)
{
max_id[q] = k;
for(int i = 23; i >= 0; i --)
{
int v = s[k] >> i & 1;
if(p)tr[q][v ^ 1] = tr[p][v ^ 1];
tr[q][v] = ++ idx;
max_id[tr[q][v]] = k;
q = tr[q][v], p = tr[p][v];
}
}
void insert(int i, int k, int p, int q)
{
if(k < 0)
{
max_id[q] = i;
return ;
}
int v = s[i] >> k & 1;
if(p)tr[q][v ^ 1] = tr[p][v ^ 1];
tr[q][v] = ++ idx;
insert(i, k - 1, tr[p][v], tr[q][v]);
max_id[q] = max(max_id[tr[q][0]], max_id[tr[q][1]]);
}
int query(int p, int l, int c)
{
for(int i = 23; i >= 0; i --)
{
int v = c >> i & 1;
if(max_id[tr[p][v ^ 1]] >= l)p = tr[p][v ^ 1];
else p = tr[p][v];
}
return c ^ s[max_id[p]];
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
s[0] = 0;
max_id[0] = -1;
root[0] = ++ idx;
insert(0, 0, root[0]);
for(int i = 1; i <= n; i ++)
{
int x;
scanf("%d", &x);
root[i] = ++ idx;
s[i] = s[i - 1] ^ x;
insert(i, root[i - 1], root[i]);
}
while(m --)
{
char op[2];
scanf("%s", op);
if(*op == 'A')
{
int x;
scanf("%d", &x);
n ++;
root[n] = ++ idx;
s[n] = s[n - 1] ^ x;
insert(n, root[n - 1], root[n]);
}
else
{
int l, r, x;
scanf("%d%d%d", &l, &r, &x);
printf("%d\n", query(root[r - 1], l - 1, s[n] ^ x));
}
}
return 0;
}
为什么要insert(0)
Shift+5
为什么要记录
max_id
呢max_id[tr[q][v]] = k;
q = tr[q][v], p = tr[p][v];
很奇怪,为什么这两行代码调换一下,就报错了呢,insert里面的
提壶灌腚
谢谢大佬
max_id[0] = -1不这样赋值的话什么情况下会出现问题?
编号0代表的是空节点,若max_id[0]取了一个在[0,n-1]范围内的数,则会在query过程中返回一个错误的值
若在[0,n-1]中选择了一个值,则在query过程中走向了一个分支,所以得到的结果也可能是错误的
感觉
max_id[q] = k;
可以不写,因为询问的时候不会判断根节点的max_id嗯,是可以不写,但是代码完整性会欠缺,其他人读代码会摸不着头脑,不是一个好习惯个人觉得
感觉可以不写
insert(0, 0, root[0]);
(毕竟里面本来都是0),这样就不会更新max_id[0]了,也就没有idx还是idx的问题了idx++
还是++idx
(神奇的markdown)