Description
A
国共有
Input
第一行包含 2 个正整数 n,q ,分别表示城市的数量和旅行者数量。第二行包含 n 个非负整数,其中第 i 个整
数 Gi 表示 i 号城市的幸运值。随后 n−1 行,每行包含两个正整数 x,y ,表示 x 号城市和 y 号城市之间有一
条道路相连。随后 q 行,每行包含两个正整数 x,y ,表示这名旅行者的旅行计划是从 x 号城市到 y 号城市。
N≤20000,Q≤200000,Gi≤260
Output
输出需要包含 q 行,每行包含 1 个非负整数,表示这名旅行者可以保留的最大幸运值。
Sample Input
4 2
11 5 7 9
1 2
1 3
1 4
2 3
1 4
Sample Output
14
11
Solution
一条路径上的最大幸运值在求出这条路径上边权集里的线性基后从高位到低位贪心取即可,问题在于如果求路径上的线性基,考虑倍增,求出从
i
点到其第
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
const int maxn=20005;
void Add(ll *b,ll a)
{
for(int i=60;i>=0;i--)
if((a>>i)&1)
{
if(!b[i])
{
b[i]=a;
return ;
}
else a^=b[i];
}
}
void Unite(ll *x,ll *y)
{
for(int i=0;i<=60;i++)
if(y[i])Add(x,y[i]);
}
int n,q,fa[maxn][16],dep[maxn];
ll base[maxn][16][61],ans[61];
vector<int>g[maxn];
void dfs(int u,int f)
{
dep[u]=dep[f]+1;
fa[u][0]=f;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(v!=f)dfs(v,u);
}
}
void LCA(int u,int v)
{
if(dep[u]<dep[v])swap(u,v);
for(int i=15;i>=0;i--)
if(dep[fa[u][i]]>=dep[v])
{
Unite(ans,base[u][i]);
u=fa[u][i];
}
if(u==v)
{
Unite(ans,base[u][0]);
return ;
}
for(int i=15;i>=0;i--)
if(fa[u][i]!=fa[v][i])
{
Unite(ans,base[u][i]);u=fa[u][i];
Unite(ans,base[v][i]);v=fa[v][i];
}
Unite(ans,base[u][0]);u=fa[u][0];
Unite(ans,base[v][0]);v=fa[v][0];
Unite(ans,base[u][0]);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)
{
ll a;
scanf("%lld",&a);
Add(base[i][0],a);
}
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
g[u].push_back(v),g[v].push_back(u);
}
dfs(1,0);
for(int j=1;j<=15;j++)
for(int i=1;i<=n;i++)
{
fa[i][j]=fa[fa[i][j-1]][j-1];
for(int k=0;k<=60;k++)base[i][j][k]=base[i][j-1][k];
Unite(base[i][j],base[fa[i][j-1]][j-1]);
}
while(q--)
{
int u,v;
scanf("%d%d",&u,&v);
memset(ans,0,sizeof(ans));
LCA(u,v);
ll res=0;
for(int i=60;i>=0;i--)res=max(res,res^ans[i]);
printf("%lld\n",res);
}
return 0;
}