題目大意:給你一顆樹,多個詢問,問你樹上任意兩點的路徑上選任意幾個點使得異或和最大。
我是參考的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;
}