题目大意:给你一颗树,多个询问,问你树上任意两点的路径上选任意几个点使得异或和最大。
我是参考的claris大神的代码(%%%),点分治,对于询问在两个子树间或者有一个在重心上的进行回答,否则把问题用链表接到询问点所在的子树上。
具体方法可以选中重心都对每个子树染色,染为这个子树的根节点。在子树处理问题之前一定要记住先把询问拖出来,然后把子树的问题清零。因为你选的是这个子树的重心开始分治,而不是根,所以这个子树的根可能就会又加入一些问题,你不清零就会重复计算一些问题和出错。
然后是对于重心到子树每个点都求一次线性基,最后暴力合并在不同子树两点的线性基就是答案(claris的线性基也是%%%%),具体可参照代码
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int N = 20010, M = 40010, Q = 200010*30, E = 200010;
int n, m, g[N], to[M], nxt[M], ok[M], np, G[N], To[Q], Nxt[Q], Np, now, all, son[N], color[N], f[N];
ll w[N], Ans[E];
struct data{ int x,y; }q[E];
struct gauss {
ll a[65];
gauss(){ for(int i=0;i<60;i++) a[i] = 0; }
inline void ins(ll x) { for(int i=59;~i;i--) if((x>>i)&1) { if(a[i]) x^=a[i]; else { a[i]=x; break; } } }
inline ll ask() {
ll ans = 0;
for(int i=59;~i;i--) if((ans^a[i]) > ans) ans ^= a[i];
return ans;
}
}h[N], tmp;
template<class T>
inline void read(T &x) {
char op; while( ((op=getchar())<'0') || (op>'9'));
x = op-'0'; while(((op=getchar())>='0') && (op<='9')) (x*=10)+=op-'0';
}
char buf[30];
template<class T>
inline void out(T x) {
int i = 0;
if(!x) putchar('0');
while(x) {buf[++i] = x%10+'0'; x/=10;}
while(i) putchar(buf[i--]);
putchar('\n');
}
inline void push(int x,int y) { nxt[++np] = g[x]; to[np] = y; g[x] = np; ok[np] = 1; }
inline void PUSH(int x,int y) { Nxt[++Np] = G[x]; To[Np] = y; G[x] = Np;}
void findG(int x, int Fa) {
f[x] = 0;
for(int i=g[x];i;i=nxt[i])
if(ok[i] && to[i] != Fa) {
int y = to[i];
findG(y, x);
f[x] = f[x] < son[y] ? son[y] : f[x];
}
f[x] = f[x] < (all-son[x]) ? (all-son[x]) : f[x];
if(f[now] > f[x]) now = x;
}
void Paint(int x,int Fa,int c) {
color[x] = c;
son[x] = 1;
h[x] = h[Fa];
h[x].ins(w[x]);
for(int i=g[x];i;i=nxt[i])
if(ok[i] && to[i] != Fa) {
int y = to[i];
Paint(y,x,c);
son[x] += son[y];
}
}
void work(int x) {
if(!G[x]) return;
f[0] = all = son[x];
if(x!=1) findG(x,now=0);
else now = 1;
h[now] = gauss();
h[now].ins(w[now]);
for(int i=g[now];i;i=nxt[i]) if(ok[i]) Paint(to[i],now,to[i]);
int t = G[x]; G[x] = 0;
for(;t;t=Nxt[t]) {
int i = To[t];
if(q[i].x == now || q[i].y == now || color[q[i].x] != color[q[i].y]) {
tmp = h[q[i].x];
for(int j=59;~j;j--)
if(h[q[i].y].a[j])tmp.ins(h[q[i].y].a[j]);
Ans[i] = tmp.ask();
}
else PUSH(color[q[i].x],i);
}
for(int i=g[now];i;i=nxt[i]) if(ok[i]) { ok[i^1] = 0; work(to[i]); }
}
int main() {
memset(g,0,sizeof(g));
memset(G,0,sizeof(G));
read(n);read(m);
int x,y;
for(int i=1;i<=n;i++) read(w[i]);
np = Np = 1;
for(int i=1;i<n;i++) {
read(x);read(y);
push(x,y);
push(y,x);
}
for(int i=1;i<=m;i++) read(q[i].x), read(q[i].y);
for(int i=1;i<=m;i++){
if(q[i].x == q[i].y) Ans[i] = w[q[i].x];
else PUSH(1,i);
}
work(1);
for(int i=1;i<=m;i++) out(Ans[i]);
return 0;
}