题意简述
给定一颗 个点的树,点带点权,不超过 。还有 个询问,每次询问两个点之间路径上的最大异或和。
思路
表示从 往上 个节点组成的线性基。 的时候线性基合并就珂以了。带三个log,两个是 ,一个是 。也就是 。虽然看起来有 ,但是你相信我那两个 乘不满。所以你能过。在 的机器上写面向对象都能过。
代码细节
这题重在模拟。代码细节蛮多的。
- lca的第一步,跳到同一高度,判断条件是deep[fa[u][k]]<=deep[v]
- lca的最后一步,要把val[u],val[v],val[fa[u][0]]的值都插入进来。联想一下求最小值你就明白这步了
- 好像没了?代码还是蛮长的,别写挂别的地方即珂
代码
#include <bits/stdc++.h>
using namespace std;
namespace Flandre_Scarlet
{
#define N 24444
#define int long long
#define F(i,l,r) for(int i=l;i<=r;++i)
#define D(i,r,l) for(int i=r;i>=l;--i)
#define Fs(i,l,r,c) for(int i=l;i<=r;c)
#define Ds(i,r,l,c) for(int i=r;i>=l;c)
#define Tra(i,u) for(int i=G.Start(u),__v=G.To(i);~i;i=G.Next(i),__v=G.To(i))
#define MEM(x,a) memset(x,a,sizeof(x))
#define FK(x) MEM(x,0)
class LB
{
public:
int d[64];
int& operator[](int id){return *(d+id);}
void Init(){FK(d);}
void Insert(int x)
{
D(i,60,0)
{
if (!(x&(1ll<<i))) continue;
if (!d[i])
{
d[i]=x;break;
}
x^=d[i];
}
}
int MaxXor()
{
int ans=0;
D(i,60,0) if ((ans^d[i])>ans) ans^=d[i];
return ans;
}
};
LB Merge(LB a,LB b)
{
D(i,60,0)
{
if (b[i]) a.Insert(b[i]);
}
return a;
}
class Graph
{
public:
int head[N];
int EdgeCount;
struct Edge
{
int To,Label,Next;
}Ed[N<<1];
void clear(int _V=N,int _E=N<<1)
{
memset(Ed,-1,sizeof(Edge)*(_E));
memset(head,-1,sizeof(int)*(_V));
EdgeCount=-1;
}
void AddEdge(int u,int v,int w=1)
{
Ed[++EdgeCount]=(Edge){v,w,head[u]};
head[u]=EdgeCount;
}
void Add2(int u,int v,int w=1) {AddEdge(u,v,w);AddEdge(v,u,w);}
int Start(int u) {return head[u];}
int To(int u){return Ed[u].To;}
int Label(int u){return Ed[u].Label;}
int Next(int u){return Ed[u].Next;}
}G;
void R1(int &x)
{
x=0;char c=getchar();int f=1;
while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=(f==1)?x:-x;
}
int n,m;int val[N];
void Input()
{
R1(n),R1(m);
F(i,1,n) R1(val[i]);
G.clear();
F(i,1,n-1)
{
int u,v;R1(u),R1(v);
G.Add2(u,v);
}
}
LB B[N][18];
int fa[N][24],deep[N];
void DFS(int u,int f)
{
deep[u]=deep[f]+1;
fa[u][0]=f;
B[u][0].Init();B[u][0].Insert(val[u]);
F(i,1,16)
{
fa[u][i]=fa[fa[u][i-1]][i-1];
B[u][i]=Merge(B[u][i-1],B[fa[u][i-1]][i-1]);
}
Tra(i,u)
{int v=__v;
if (v==f) continue;
DFS(v,u);
}
}
int LCA(int u,int v)
{
LB ans;ans.Init();
if (deep[u]<deep[v]) swap(u,v);
D(i,16,0)
{
if (deep[fa[u][i]]>=deep[v])
{
ans=Merge(ans,B[u][i]);
u=fa[u][i];
}
}
if (u==v)
{
ans.Insert(val[u]);
return ans.MaxXor();
}
D(i,16,0)
{
if (fa[u][i]!=fa[v][i])
{
ans=Merge(ans,B[u][i]);
ans=Merge(ans,B[v][i]);
u=fa[u][i],v=fa[v][i];
}
}
ans.Insert(val[u]);ans.Insert(val[v]);
ans.Insert(val[fa[u][0]]);
return ans.MaxXor();
}
void Soviet()
{
DFS(1,1);
F(i,1,m)
{
int u,v;R1(u),R1(v);
printf("%lld\n",LCA(u,v));
}
}
#define Flan void
Flan IsMyWife()
{
Input();
Soviet();
}
#undef int //long long
}
int main()
{
Flandre_Scarlet::IsMyWife();
getchar();getchar();
return 0;
}