[SCOI2016] 幸运数字
题目描述
A 国共有 \(n\) 座城市,这些城市由 \(n - 1\) 条道路相连,使得任意两座城市可以互达,且路径唯一。每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征。
一些旅行者希望游览 A 国。旅行者计划乘飞机降落在 \(x\) 号城市,沿着 \(x\) 号城市到 \(y\) 号城市之间那条唯一的路径游览,最终从 \(y\) 城市起飞离开 A 国。在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上。然而,幸运是不能简单叠加的,这一点游览者也十分清楚。他们迷信着幸运数字是以异或的方式保留在自己身上的。
例如,游览者拍了 \(3\) 张照片,幸运值分别是 \(5, 7, 11\),那么最终保留在自己身上的幸运值就是 \(5 \operatorname{xor} 7 \operatorname{xor} 11 = 9\)。
有些聪明的游览者发现,只要选择性地进行拍照,便能获得更大的幸运值。例如在上述三个幸运值中,只选择 \(5\) 和 \(11\) ,可以保留的幸运值为 \(14\) 。现在,一些游览者找到了聪明的你,希望你帮他们计算出在他们的行程安排中可以保留的最大幸运值是多少。
提示
对于 \(100 \%\) 的数据,保证 \(n \leq 2 \times 10^4, q \leq 2 \times 10^5, G_i \leq 2^{60}\)。
Solution:
我们知道线性基是可以合并的,我们先对于每个点记录该点到根这条路径上所有点构成的线性基,但在插入时,对于相同的位,我们优先取更深的那个点,那么我们在从这个树上取出一条路径上的线性基时,直接判断这个点的深度是否大于 lca 然后我们就能取出这条路径上的线性基,直接最大化答案就好了。
Code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
const int inf=65;
const int lg=15;
int n,m,e_cnt;
int head[N],a[N],dep[N],base[inf];
int d[N][inf],pos[N][inf],fa[N][inf];
struct Edge{int to,nxt;
}e[N<<1];
void add(int x,int y)
{e[++e_cnt]={y,head[x]};head[x]=e_cnt;
}
void ins(int x,int d[],int pos[])
{int v=a[x];for(int i=60;i>=0;i--){if(v&(1ll<<i)){if(!d[i]){d[i]=v;pos[i]=x;break;}if(dep[x]>dep[pos[i]]){swap(x,pos[i]);swap(d[i],v);}v^=d[i];}}
}
void dfs(int x)
{dep[x]=dep[fa[x][0]]+1;for(int i=1;i<=lg;i++){fa[x][i]=fa[fa[x][i-1]][i-1];}for(int i=0;i<=60;i++){pos[x][i]=pos[fa[x][0]][i];d[x][i]=d[fa[x][0]][i];}ins(x,d[x],pos[x]);for(int i=head[x];i;i=e[i].nxt){int to=e[i].to;if(to==fa[x][0])continue;fa[to][0]=x;dfs(to);}
}
int LCA(int x,int y)
{if(dep[x]<dep[y])swap(x,y);for(int i=lg;i>=0;i--){if(dep[fa[x][i]]>=dep[y])x=fa[x][i];}if(x==y)return x;for(int i=lg;i>=0;i--){if(fa[x][i]!=fa[y][i]){x=fa[x][i];y=fa[y][i];}}return fa[x][0];
}
int ANS(int x,int y,int lca)
{for(int i=60;i>=0;i--){if(dep[pos[x][i]]>=dep[lca]){base[i]=d[x][i];}else base[i]=0;}for(int i=60;i>=0;i--){if(dep[pos[y][i]]>=dep[lca]){int p=d[y][i];if(!p)continue;for(int j=i;j>=0;j--){if(p&(1ll<<j)){if(!base[j]){base[j]=p;break;}p^=base[j];}}}}int ans=0;for(int i=60;i>=0;i--){ans= (ans^base[i])>ans ? ans^base[i] : ans;}return ans;
}
void work()
{cin>>n;cin>>m;for(int i=1;i<=n;i++){scanf("%lld",&a[i]);}for(int i=1,x,y;i<n;i++){scanf("%lld%lld",&x,&y);add(x,y);add(y,x);}dfs(1);for(int i=1,x,y;i<=m;i++){scanf("%lld%lld",&x,&y);int lca=LCA(x,y);int ans=ANS(x,y,lca);printf("%lld\n",ans);}
}
#undef int
int main()
{ //freopen("P3292_1.in","r",stdin);freopen("P3292.out","w",stdout);work();
}