链接:https://www.luogu.org/problemnew/show/P4592
题目描述
现在有一颗以 11 为根节点的由 nn 个节点组成的树,树上每个节点上都有一个权值 v_ivi 。现在有 QQ 次操作,操作如下:
- 1;x;y1xy :查询节点 xx 的子树中与 yy 异或结果的最大值
- 2;x;y;z2xyz :查询路径 xx 到 yy 上点与 zz 异或结果最大值
输入输出格式
输入格式:
第一行是两个数字 n,Qn,Q ;
第二行是 nn 个数字用空格隔开,第 ii 个数字 v_ivi 表示点 ii 上的权值
接下来 n-1n−1 行,每行两个数, x,yx,y ,表示节点 xx 与 yy 之间有边
接下来 QQ 行,每一行为一个查询,格式如上所述.
输出格式:
对于每一个查询,输出一行,表示满足条件的最大值。
输入输出样例
输入样例#1: 复制
7 5 1 3 5 7 9 2 4 1 2 1 3 2 4 2 5 3 6 3 7 1 3 5 2 4 6 3 1 5 5 2 5 7 2 1 1 9
输出样例#1: 复制
7 6 12 11 14
说明
对于 10\%10% 的数据,有 1<n,,Q≤100
对于 20\%20% 的数据,有 1<n,,Q≤1000
对于 40\%40% 的数据,有 1<n,,Q≤10000
对于 100\%100% 的数据,有 1<n,Q≤100000
对于 100\%100% 的数据,有查询 11 中的y≤2^30 ,查询 22 中的 z≤2^30 。
题解:贪心+可持续化Trie树; 对于子树查询用dfn序; 对于链上查询, 我们对每个点建一个他到根节点的Trie树,然后跑lca,又变成了序列上的查询;
好久不写倍增都错了
#include<bits/stdc++.h> using namespace std; const int M = 100005, Trie_M = 1e7; #define ll long long #define For(a, b, c) for(int a = b; a <= c; a++) #define ex(i, u) for(int i = h[u]; i; i = G[i].nxt) int dep[M], out[M], dfn[M], val[M], nval[M], root[M], h[M], anc[M][20], tot, idx, cnt; ll bin[35]; int read(){ int x=0,f=1;char c=getchar(); while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();} while(c<='9'&&c>='0'){x=x*10+c-'0';c=getchar();} return x*=f; } struct edge{ int v, nxt;}G[M << 1]; void add(int u, int v){G[++tot].v = v; G[tot].nxt = h[u]; h[u] = tot;} struct Trie{ int root[M]; struct Tree{ int ch[2], ptr[2]; }tree[Trie_M]; void ins(int f, int &now, int x, int c = 0){ now = ++cnt; int res = now; tree[res] = tree[f]; for(int i = 31; i >= 0; i--){ int d = (x & bin[i]) ? 1 : 0; tree[res].ch[d]++; int p = ++cnt; tree[res].ptr[d] = p; f = tree[f].ptr[d]; tree[p] = tree[f]; res = tree[res].ptr[d]; //printf("%d ", d); } //printf(" "); } ll query(int lf, int rg, int x){ ll ret = 0; for(int i = 31; i >= 0; i--){ int d = (x & bin[i]) ? 1 : 0; if(tree[rg].ch[d^1] - tree[lf].ch[d^1]){ lf = tree[lf].ptr[d^1], rg = tree[rg].ptr[d^1]; ret += bin[i]; } else lf = tree[lf].ptr[d], rg = tree[rg].ptr[d]; } return ret; } }xuelie, zishu; void dfs(int u, int f){ dfn[u] = ++idx; nval[idx] = val[u]; dep[u] = dep[f] + 1; anc[u][0] = f; For(p, 1, 19) anc[u][p] = anc[anc[u][p - 1]][p - 1]; xuelie.ins(xuelie.root[f], xuelie.root[u], val[u]); ex(i, u){ int v = G[i].v; if(v == f)continue; dfs(v, u); } out[u] = idx; } int find_lca(int u, int v){ if(dep[u] < dep[v])swap(u, v); int t = dep[u] - dep[v]; for(int p = 0; t; t >>= 1, p++) if(t & 1)u = anc[u][p]; if(u == v)return u; for(int p = 19; p >= 0; p--) if(anc[u][p] != anc[v][p]) u = anc[u][p], v = anc[v][p]; return anc[u][0]; } int main(){ //freopen("data.out","r",stdin); //freopen("my.out","w",stdout); int n, Q; bin[0] = 1; For(i, 1, 32) bin[i] = bin[i - 1] << 1; scanf("%d%d", &n, &Q); For(i, 1, n) val[i] = read(); For(i, 1, n-1){ int u = read(), v = read(); add(u, v); add(v, u); } dfs(1, 0); For(i, 1, n) zishu.ins(zishu.root[i - 1], zishu.root[i], nval[i]); int opt, x, y, z; For(i, 1, Q){ opt = read(), x = read(), y = read(); if(opt == 1){ printf("%lld ", zishu.query(zishu.root[dfn[x] - 1], zishu.root[out[x]], y)); } else { int z = read(); int flca = anc[find_lca(x, y)][0]; //printf("%d ", flca); ll ans = max(xuelie.query(xuelie.root[flca], xuelie.root[x], z), xuelie.query(xuelie.root[flca], xuelie.root[y], z)); printf("%lld ",ans); } } } /* 7 5 1 3 5 7 9 2 4 1 2 1 3 2 4 2 5 3 6 3 7 1 3 5 2 4 6 3 1 5 5 2 5 7 2 1 1 9 */