题意:询问树上结点x到结点y路上上的权值异或z的最大值。
任意结点权值 ≤ 2^16,可以想到用字典树。
但是因为是询问某条路径上的字典树,将字典树可持续化,字典树上的结点保存在这条路径上的二进制数。
按照dfs序建树,结点u的字典树表示u到根结点路径上的字典树。
如果两个结点u和v,在同一条通往根结点的路径上,将会满足可减性。
因此只需要知道u、v、lca和fa[lca]四个结点的字典树就可以回答了。
/********************************************************* * ------------------ * * author AbyssFish * **********************************************************/ #include<cstdio> #include<iostream> #include<string> #include<cstring> #include<queue> #include<vector> #include<stack> #include<map> #include<set> #include<algorithm> #include<cmath> #include<numeric> #include<climits> using namespace std; const int maxn = 1e5+5; const int maxd = 16; const int maxnds = (maxd+1)*maxn; int hd[maxn], nx[maxn<<1], to[maxn<<1], ec; void add_edge(int u,int v) { nx[ec] = hd[u]; to[ec] = v; hd[u] = ec++; } void init_g(int n){ memset(hd+1,0xff,n*sizeof(int)); ec = 0; } #define eachedge int i = hd[u]; ~i; i = nx[i] #define ifvalid int v = to[i]; if(v == fa[u]) continue; struct Node { int ch[2]; int v; }p[maxnds]; int tot; int n,m; int stk[maxd+5]; inline int *dcmp(int x) { for(int i = 0; i < maxd; i++){ stk[i] = x>>i&1; } return stk; } void build(int *o, int v) { int *s = dcmp(v); for(int i = maxd-1; i >= 0; i--){ o = &(p[*o].ch[s[i]]); p[++tot] = p[*o]; *o = tot; p[*o].v++; } } int a[maxn]; int fa[maxn]; int root[maxn]; void dfs_build(int u,int f = 0) { p[root[u] = ++tot] = p[root[fa[u] = f]]; build(root+u,a[u]); for(eachedge){ ifvalid dfs_build(v,u); } } int *c_cmp; bool cmp_id(int i,int j){ return c_cmp[i] < c_cmp[j]; } int dep[maxn]; int path[maxn<<1]; int pid[maxn]; int dfs_clk; void get_path(int u,int d) { dep[u] = d; path[++dfs_clk] = u; pid[u] = dfs_clk; for(eachedge){ ifvalid get_path(v,d+1); path[++dfs_clk] = u; } } struct SparseTable { int mxk[maxn<<1]; int d[maxn<<1][18]; void init(int *mp,int *r, int n) { mxk[0] = -1; for(int i = 1; i <= n; i++){ d[i][0] = r[i]; mxk[i] = ((i&(i-1)) == 0) ?mxk[i-1]+1:mxk[i-1]; } c_cmp = mp; for(int j = 1; j <= mxk[n]; j++){ int t = (1<<j)-1, s = 1<<(j-1); for(int i = 1; i + t <= n; i++){ d[i][j] = min(d[i][j-1],d[i+s][j-1],cmp_id); } } } int RMQ(int l,int r) { int k = mxk[r-l]; return min(d[l][k],d[r-(1<<k)][k],cmp_id); } }rmq; void lca_init(int u) { dfs_clk = 0; get_path(u,1); rmq.init(dep,path,dfs_clk); } int q_lca(int u, int v) { if(pid[u] > pid[v]) swap(u,v); return rmq.RMQ(pid[u],pid[v]+1); } vector<int> Tree; int cal_ch(int d) { int re = 0; for(int i = 0; i < (int)Tree.size(); i++){ int o = Tree[i]; re += o >= 0? p[p[o].ch[d]].v : -p[p[-o].ch[d]].v; } return re; } void dump(int d) { for(int i = 0; i < (int)Tree.size(); i++){ int &o = Tree[i]; o = o >= 0? p[o].ch[d] : -p[-o].ch[d]; } } int query(int x,int y,int z) { int re = z&~((1<<16)-1); int *s = dcmp(z); Tree.clear(); Tree.push_back(root[x]); Tree.push_back(root[y]); int lca = q_lca(x,y); Tree.push_back(-root[lca]); Tree.push_back(-root[fa[lca]]); int tmp = 0; for(int i = maxd-1; i >= 0; i--, tmp <<= 1){ int d = s[i]^1; if(cal_ch(d)){ tmp |= 1; dump(d); } else dump(d^1); } return re|(tmp>>1); } void solve() { for(int i = 1; i <= n; i++){ scanf("%d",a+i); } init_g(n); for(int i = 1,u,v; i < n; i++){ scanf("%d%d",&u,&v); add_edge(u,v); add_edge(v,u); } tot = 0; dfs_build(1); lca_init(1); for(int i = 0, x, y, z; i < m; i++){ scanf("%d%d%d",&x,&y,&z); printf("%d\n",query(x,y,z)); } } //#define LOCAL int main() { #ifdef LOCAL freopen("in.txt","r",stdin); #endif //p[0] = {{0,0},0}; //root[0] = 0; while(~scanf("%d%d",&n,&m)){ solve(); } return 0; }