可持久化01Tire&DFS序
字典树,前面的AC自动机里面用的东西
\(01Tire\) 可以用来解决 \(xor\) 问题
struct{
int c[N][2],tot;
int getnode(){
tot++;
c[tot][0] = c[tot][1] = 0;
return tot;
}
void insert(int val){
int u = 0;
for(int i = maxbit;i >= 0;i--){
int v = (val & (1 << i) ) ? 1 : 0;
if(!c[u][v])c[u][v] = getnode();
u = c[u][v];
}
}
void init(){
c[0][0] = c[0][1] = 0;
tot = 0;
}
}Tire;
动态开点
int getnode(){
tot++;
c[tot][0] = c[tot][1] = 0;
return tot;
}
动态开点的好处就是在多数数据的时候不需要 memset
数据插入
void insert(int val){
int u = 0;
for(int i = maxbit;i >= 0;i--){
int v = (val & (1 << i) ) ? 1 : 0;
if(!c[u][v])c[u][v] = getnode();
u = c[u][v];
}
}
从高位到低位插入到01字典树中
01Tire
给一个集合,每次询问给出 \(x\) ,输出集合中的数 \(k\) 使得它们异或最大。
注意是输出数,不是输出最大的异或值
思路:
用集合里的数建 \(01Tire\) ,将 \(x\) 按位取反,从高位开始匹配,匹配失败则换一边
#include<bits/stdc++.h>
using namespace std;
const int N = 2e6 + 10;
const int maxbit = 30; //int不能开31,intmax = (1<<31)-1
struct{
int c[N][2],tot;
int getnode(){
tot++;
c[tot][0] = c[tot][1] = 0;
return tot;
}
void insert(int val){
int u = 0;
for(int i = maxbit;i >= 0;i--){
int v = (val & (1 << i) ) ? 1 : 0;
if(!c[u][v])c[u][v] = getnode();
u = c[u][v];
}
}
int query(int val){
int u = 0;
int ans = 0;
for(int i = maxbit;i >= 0;i--){
int v = (val & (1 << i)) ? 0 : 1;
if(!c[u][v]) v ^= 1;
if(v)ans += (1 << i);
u = c[u][v];
}
return ans;
}
void init(){
c[0][0] = c[0][1] = 0;
tot = 0;
}
}Tire;
int n,m,x,T;
int main(){
scanf("%d",&T);
for(int c = 1;c <= T;c++){
Tire.init();
scanf("%d%d",&n,&m);
for(int i = 0;i < n;i++){
scanf("%d",&x);
Tire.insert(x);
}
printf("Case #%d:\n",c);
for(int i = 0;i < m;i++){
scanf("%d",&x);
printf("%d\n",Tire.query(x));
}
}
}
可持久化Tire
区间查询
搞一个可持久化的Tire就好了
插入:
// root[i] = insert(root[i-1],v,val);
int insert(int pre, int v, int val) {
int u = getnode();
int ans = u;
for (int i = maxbit; i >= 0; i--) {
c[u][0] = c[pre][0];
c[u][1] = c[pre][1]; //复制信息
int x = val & (1 << i) ? 1 : 0;
c[u][x] = getnode();//开点
u = c[u][x]; // 0 是空的节点,所以可以一直这样迭代
pre = c[pre][x];
}
return ans;
}
其实也很简单,就是复制之前的信息,然后开点。
查询:
由于开点是一个一个分配的,所以只要
id < root[l]
就不是区间内,所以只要加上这一个判断就跟之前的一样。
int query(int l, int r, int x) {
int MinID = root[l];
int u = root[r];
int ans = 0;
for (int i = maxbit; i >= 0; i--) {
int now = (x & (1 << i)) ? 0 : 1;
if (c[u][now] and c[u][now] >= MinID) {
u = c[u][now];
ans += (1 << i);
}
else {
u = c[u][now ^ 1];
}
}
return ans;
}
完整代码
/*
* @Author: zhl
* @Date: 2020-10-13 09:46:47
*/
// #@@# . .,,,.
// /@@@@@& @@@@@&
// /@@@@ @@@@
// /% *(#%,,,,&%, .@@.
// ( ./* ,*. %
// ( * , .
// @@ ,. ., @@ @@@@,
// &@@@@. ., ,. . /@@@@@&&&&@@@@@.
// @@@@@@@@@@@@#* .,%@@@@@@@@@@@@@@@@@
// @@@@@@@, @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// . @@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@%%%&%&&@&%@&
// . .//, &@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#%%&&
// (/,,, * @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&%%%@@/
// ((*//,,* #/&# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#%%@@&@@@@@*
// #((###%%%%%#( .&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%&&@@%/@@@@@@
// %####%%%%%%%%%%,* @@@@@@@@@# @@@@@@@@@&&&@@
// ####%%%%%%%%%%/ @@@@@@@, @@@@@@@@@@&&@&
// (##((#%%%%%%%%# &@@. @@&...&%@@@@@&&
// /(((##%%%%%%%% @%,
// /((##%%%%%%%%
// ,#%&%#
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = a;i <= b;i++)
#define repE(i,u) for(int i = head[u];i;i = E[i].next)
#define swap(a,b) a^=b,b^=a,a^=b
const int N = 2e6 + 10;
const int maxbit = 30;
struct {
int root[N], c[N][2], tot;
void init() {
c[0][0] = c[0][1] = 0;
tot = 0;
root[0] = 0;
}
int getnode() {
tot++;
c[tot][0] = c[tot][1] = 0;
return tot;
}
//root[v] = insret(Tire.root[v-1], v, val);
int insert(int pre, int v, int val) {
int u = getnode();
int ans = u;
for (int i = maxbit; i >= 0; i--) {
c[u][0] = c[pre][0];
c[u][1] = c[pre][1];
int x = val & (1 << i) ? 1 : 0;
c[u][x] = getnode();
u = c[u][x];
pre = c[pre][x];
}
return ans;
}
int query(int l, int r, int x) {
int Treesize = maxbit + 2;
int MinID = root[l];
int u = root[r];
int ans = 0;
for (int i = maxbit; i >= 0; i--) {
int now = (x & (1 << i)) ? 0 : 1;
if (c[u][now] and c[u][now] >= MinID) {
u = c[u][now];
ans += (1 << i);
}
else {
u = c[u][now ^ 1];
}
}
return ans;
}
}Tire;
int n, m, l, r, x;
int A[N];
int main() {
scanf("%d%d", &n, &m);
Tire.init();
for (int i = 1; i <= n; i++) {
scanf("%d", A + i);
Tire.root[i] = Tire.insert(Tire.root[i-1],i,A[i]);
}
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &x, &l, &r);
printf("%d\n", Tire.query(l + 1, r + 1, x));
}
}
DFS序 + 可持久化Tire
思路:
DFS序,转化为第二个问题
dfs序:
void dfs(int u, int p) {
L[u] = ++cnt;
val[cnt] = A[u];
repE(i, u) {
if (E[i].to == p)continue;
dfs(E[i].to, u);
}
R[u] = ++cnt;
val[cnt] = A[u];
}
完整代码:
/*
* @Author: zhl
* @Date: 2020-10-13 11:06:09
*/
// #@@# . .,,,.
// /@@@@@& @@@@@&
// /@@@@ @@@@
// /% *(#%,,,,&%, .@@.
// ( ./* ,*. %
// ( * , .
// @@ ,. ., @@ @@@@,
// &@@@@. ., ,. . /@@@@@&&&&@@@@@.
// @@@@@@@@@@@@#* .,%@@@@@@@@@@@@@@@@@
// @@@@@@@, @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
// . @@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@%%%&%&&@&%@&
// . .//, &@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#%%&&
// (/,,, * @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@&%%%@@/
// ((*//,,* #/&# @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#%%@@&@@@@@*
// #((###%%%%%#( .&@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%&&@@%/@@@@@@
// %####%%%%%%%%%%,* @@@@@@@@@# @@@@@@@@@&&&@@
// ####%%%%%%%%%%/ @@@@@@@, @@@@@@@@@@&&@&
// (##((#%%%%%%%%# &@@. @@&...&%@@@@@&&
// /(((##%%%%%%%% @%,
// /((##%%%%%%%%
// ,#%&%#
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = a;i <= b;i++)
#define repE(i,u) for(int i = head[u];i;i = E[i].next)
#define swap(a,b) a^=b,b^=a,a^=b
const int N = 2e5 + 10;
//cnm 1e6 一直T
//N 5e5,m 5e5
struct Edge {
int to, next;
}E[N << 1];
int head[N], tot;
void addEdge(int from, int to) {
E[++tot] = Edge{ to,head[from] };
head[from] = tot++;
}
const int maxbit = 30;
struct {
int root[N<<5], c[N<<5][2], tot;
void init() {
c[0][0] = c[0][1] = 0;
tot = 0;
root[0] = 0;
}
int getnode() {
tot++;
c[tot][0] = c[tot][1] = 0;
return tot;
}
//root[v] = insret(Tire.root[v-1], v, val);
int insert(int pre, int v, int val) {
int u = getnode();
int ans = u;
for (int i = maxbit; i >= 0; i--) {
c[u][0] = c[pre][0];
c[u][1] = c[pre][1];
int x = val & (1 << i) ? 1 : 0;
c[u][x] = getnode();
u = c[u][x];
pre = c[pre][x];
}
return ans;
}
int query(int l, int r, int x) {
int Treesize = maxbit + 2;
int MinID = root[r] - Treesize * (r - l);
int u = root[r];
int ans = 0;
for (int i = maxbit; i >= 0; i--) {
int now = (x & (1 << i)) ? 0 : 1;
if (c[u][now] and c[u][now] >= MinID) {
u = c[u][now];
ans += (1 << i);
}
else {
u = c[u][now ^ 1];
}
}
return ans;
}
}Tire;
int n, q, l, r, x;
int A[N];
int cnt;
int val[N << 1], L[N], R[N];
void dfs(int u, int p) {
L[u] = ++cnt;
val[cnt] = A[u];
repE(i, u) {
if (E[i].to == p)continue;
dfs(E[i].to, u);
}
R[u] = ++cnt;
val[cnt] = A[u];
}
int main() {
while (scanf("%d%d", &n, &q) == 2) {
memset(head, 0, sizeof(int) * (n + 10));
tot = 0; Tire.init();
for (int i = 1; i <= n; i++) {
scanf("%d", A + i);
}
for (int i = 1; i < n; i++) {
scanf("%d", &l);
addEdge(l, i + 1);
addEdge(i + 1, l);
}
cnt = 0;
dfs(1, -1);
for (int i = 1; i <= cnt; i++) {
Tire.root[i] = Tire.insert(Tire.root[i - 1], i, val[i]);
}
for (int i = 0; i < q; i++) {
scanf("%d%d", &l, &x);
printf("%d\n", Tire.query(L[l], R[l], x));
}
}
}
LCA + 可持久化Tire
两种询问,
1 x z,询问 x 的子树与 z 异或的最大值
2 x y z,询问路径与 z 异或的最大值
思路:
建两颗可持久化Tire,一颗按dfs顺序建,一颗每个点接到它的父节点,也是树型结构。
void dfs(int u, int p) {
id[u] = ++cnt;
fa[u][0] = p; dep[u] = dep[p] + 1;
for (int x = 1; (1 << x) < dep[u]; x++) {
fa[u][x] = fa[fa[u][x - 1]][x - 1];
}
Tire1.root[cnt] = Tire1.insert(Tire1.root[cnt - 1], A[u]);
Tire2.root[cnt] = Tire2.insert(Tire2.root[id[p]], A[u]);
sz[u] = 1;
repE(i, u) {
int v = E[i].to;
if (v == p)continue;
dfs(v, u);
sz[u] += sz[v];
}
}
完整代码
/*
* @Author: zhl
* @Date: 2020-10-14 10:12:23
*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = a;i <= b;i++)
#define repE(i,u) for(int i = head[u];i;i = E[i].next)
using namespace std;
const int N = 5e5 + 10;
struct Edge {
int to, next;
}E[N << 1];
int head[N], tot;
void addEdge(int from, int to) {
E[++tot] = Edge{ to,head[from] };
head[from] = tot++;
}
int A[N];
int n, m;
const int maxbit = 30;
struct {
int c[N << 5][2], root[N], tot;
int getnode() {
tot++;
c[tot][0] = c[tot][1] = 0;
return tot;
}
void init() {
c[0][0] = c[0][1] = 0;
tot = 0;
}
int insert(int pre, int val) {
int u = getnode();
int ans = u;
for (int i = maxbit; i >= 0; i--) {
c[u][0] = c[pre][0];
c[u][1] = c[pre][1];
int x = val & (1 << i) ? 1 : 0;
c[u][x] = getnode();
u = c[u][x];
pre = c[pre][x];
}
return ans;
}
int query(int l, int r, int val) {
int minID = root[l];
int u = root[r];
int ans = 0;
for (int i = maxbit; i >= 0; i--) {
int now = (val & (1 << i)) ? 0 : 1;
if (c[u][now] and c[u][now] >= minID) {
ans += (1 << i);
u = c[u][now];
}
else u = c[u][now ^ 1];
}
return ans;
}
}Tire1, Tire2;
int sz[N], id[N], cnt, fa[N][32], dep[N];
void dfs(int u, int p) {
id[u] = ++cnt;
fa[u][0] = p; dep[u] = dep[p] + 1;
for (int x = 1; (1 << x) < dep[u]; x++) {
fa[u][x] = fa[fa[u][x - 1]][x - 1];
}
Tire1.root[cnt] = Tire1.insert(Tire1.root[cnt - 1], A[u]);
Tire2.root[cnt] = Tire2.insert(Tire2.root[id[p]], A[u]);
sz[u] = 1;
repE(i, u) {
int v = E[i].to;
if (v == p)continue;
dfs(v, u);
sz[u] += sz[v];
}
}
int LCA(int x, int y) {
if (dep[x] < dep[y])swap(x, y);
while (dep[x] != dep[y]) {
int u = dep[x] - dep[y];
int v = 0;
while (!(u & (1 << v)))v++;
x = fa[x][v];
}
while (x != y) {
int v = 0;
while (fa[x][v] != fa[y][v])v++;
x = fa[x][max(0, v - 1)]; y = fa[y][max(0, v - 1)];
}
return x;
}
int main() {
scanf("%d%d", &n, &m);
rep(i, 1, n)scanf("%d", A + i);
rep(i, 1, n - 1) {
int x, y; scanf("%d%d", &x, &y);
addEdge(x, y); addEdge(y, x);
}
dfs(1, 0);
rep(i, 1, m) {
int op, a, b, x; scanf("%d", &op);
if (op == 1) {
scanf("%d%d", &a, &x);
printf("%d\n", Tire1.query(id[a], id[a] + sz[a] - 1, x));
}
else {
scanf("%d%d%d", &a, &b, &x);
int u = LCA(a, b);
printf("%d\n", max(Tire2.query(id[u], id[a], x), Tire2.query(id[u], id[b], x)));
}
}
}
路径查询
/*
* @Author: zhl
* @Date: 2020-10-14 10:12:23
*/
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = a;i <= b;i++)
#define repE(i,u) for(int i = head[u];i;i = E[i].next)
using namespace std;
const int N = 2e5 + 10;
struct Edge {
int to, next;
}E[N << 1];
int head[N], tot;
void addEdge(int from, int to) {
E[++tot] = Edge{ to,head[from] };
head[from] = tot++;
}
int A[N];
int n, m;
const int maxbit = 30;
struct {
int c[N << 5][2], root[N], tot;
int getnode() {
tot++;
c[tot][0] = c[tot][1] = 0;
return tot;
}
void init() {
c[0][0] = c[0][1] = 0;
tot = 0;
}
int insert(int pre, int val) {
int u = getnode();
int ans = u;
for (int i = maxbit; i >= 0; i--) {
c[u][0] = c[pre][0];
c[u][1] = c[pre][1];
int x = val & (1 << i) ? 1 : 0;
c[u][x] = getnode();
u = c[u][x];
pre = c[pre][x];
}
return ans;
}
int query(int l, int r, int val) {
int minID = root[l];
int u = root[r];
int ans = 0;
for (int i = maxbit; i >= 0; i--) {
int now = (val & (1 << i)) ? 0 : 1;
if (c[u][now] and c[u][now] >= minID) {
ans += (1 << i);
u = c[u][now];
}
else u = c[u][now ^ 1];
}
return ans;
}
}Tire;
int sz[N], id[N], cnt, fa[N][32], dep[N];
void dfs(int u, int p) {
id[u] = ++cnt;
fa[u][0] = p; dep[u] = dep[p] + 1;
sz[u] = 1;
for (int x = 1; (1 << x) < dep[u]; x++) {
fa[u][x] = fa[fa[u][x - 1]][x - 1];
}
Tire.root[cnt] = Tire.insert(Tire.root[id[p]], A[u]);
repE(i, u) {
int v = E[i].to;
if (v == p)continue;
dfs(v, u);
sz[u] += sz[v];
}
}
int LCA(int x, int y) {
if (dep[x] < dep[y])swap(x, y);
while (dep[x] != dep[y]) {
int u = dep[x] - dep[y];
int v = 0;
while (!(u & (1 << v)))v++;
x = fa[x][v];
}
while (x != y) {
int v = 0;
while (fa[x][v] != fa[y][v])v++;
x = fa[x][max(0, v - 1)]; y = fa[y][max(0, v - 1)];
}
return x;
}
int main() {
while (~scanf("%d%d", &n, &m)) {
Tire.init();
tot = 0;
cnt = 0;
rep(i, 1, n) {
head[i] = 0;
memset(fa[i], 0, sizeof(fa[i]));
}
rep(i, 1, n)scanf("%d", A + i);
rep(i, 1, n - 1) {
int x, y; scanf("%d%d", &x, &y);
addEdge(x, y); addEdge(y, x);
}
dfs(1, 0);
rep(i, 1, m) {
int a, b, x;
scanf("%d%d%d", &a, &b, &x);
int u = LCA(a, b);
printf("%d\n", max(Tire.query(id[u], id[a], x), Tire.query(id[u], id[b], x)));
}
}
}