链接
https://www.luogu.org/problemnew/show/P3292
https://ac.nowcoder.com/acm/problem/20308
做题的经过(可以跳过)
这不是树上倍增维护线性基的裸题吗
然而我写了一整天
故事是这样的:
我先写了个自认为
q
l
o
g
3
qlog^3
qlog3的树剖+线段树维护区间线性基,然后
T
T
T了,事后发现原来这个算法的复杂度是
q
×
(
6
0
2
)
×
l
o
g
2
n
q\times (60^2) \times log^2n
q×(602)×log2n(这不妥妥
T
T
T掉吗)
然后我又写了个真的是
q
l
o
g
3
qlog^3
qlog3的倍增,谁知道洛谷机器慢的要死,还是
T
T
T了
然后我又写了个
q
l
o
g
2
qlog^2
qlog2的倍增,洛谷上还是
T
L
E
TLE
TLE,我就开始怀疑人生,结果开了
O
2
O2
O2就过了,还挺快…
题解
就是个裸题,树上倍增维护线性基
查询的时候,最直接的做法就是一边往上跳一边查询,这样复杂度是
O
(
q
l
o
g
2
n
l
o
g
2
2
60
)
O(q\ log_2n\ log_22^{60})
O(q log2n log2260)
优化可以效仿序列上的
R
M
Q
RMQ
RMQ,先求
l
c
a
lca
lca,这样我就知道了我要跳的区间的长度,这样求出
l
o
g
2
(
log_2(
log2(区间长度
)
)
),就可以把原来的
O
(
l
o
g
2
n
)
O(log_2n)
O(log2n)次合并线性基优化到合并
O
(
1
)
O(1)
O(1)次
代码
#include <bits/stdc++.h>
#define maxn 20010
#define maxk 15
#define cl(x) memset(x,0,sizeof(x))
using namespace std;
typedef long long ll;
ll g[maxn], N, Q;
struct Graph
{
int etot, head[maxn], to[maxn<<1], next[maxn<<1], w[maxn<<1], N;
void clear()
{
int i;
for(i=1;i<=N;i++)head[i]=0;
for(i=1;i<=etot;i++)to[i]=next[i]=w[i]=0;
N=etot=0;
}
void adde(int a, int b, int c){to[++etot]=b;w[etot]=c;next[etot]=head[a];head[a]=etot;}
}G;
ll read(ll x=0)
{
ll c, f(1);
for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
for(;isdigit(c);c=getchar())x=x*10+c-0x30;
return f*x;
}
struct LinearBasis
{
ll b[70];
void clear(){cl(b);}
void insert(ll t)
{
for(ll k(59);~k;k--)
if(t&(1ll<<k))
{
if(!b[k])b[k]=t;
t^=b[k];
}
}
void insert(ll *a, ll len)
{
for(auto i(0);i<len;i++)insert(a[i]);
}
bool check(ll x)
{
for(ll k(59);~k;k--)
if(x&(1ll<<k))x^=b[k];
return !x;
}
};
struct Doubling_LCA
{
int f[maxn][maxk+2], depth[maxn];
LinearBasis lb[maxn][maxk+2];
void clear(){cl(f), cl(lb), cl(depth);}
void dfs(Graph &G, int pos, int pre)
{
for(auto k=1;(1<<k)<=depth[pos];k++)f[pos][k]=f[f[pos][k-1]][k-1];
for(auto k=1;(1<<k)<=depth[pos];k++)
{
lb[pos][k]=lb[pos][k-1];
lb[pos][k].insert(lb[f[pos][k-1]][k-1].b,63);
}
for(auto p(G.head[pos]);p;p=G.next[p])
if(G.to[p]!=pre)
{
f[G.to[p]][0]=pos;
lb[G.to[p]][0].insert(g[G.to[p]]);
depth[G.to[p]]=depth[pos]+1;
dfs(G,G.to[p],pos);
}
}
void run(Graph &G, int root)
{
depth[root]=1;
lb[root][0].insert(g[root]);
dfs(G,root,0);
}
int q(int x, int y)
{
if(depth[x]<depth[y])swap(x,y);
for(auto k(maxk);~k;k--)
if(depth[f[x][k]]>=depth[y])
x=f[x][k];
if(x==y)return x;
for(auto k(maxk);~k;k--)
if(f[x][k]!=f[y][k])
x=f[x][k], y=f[y][k];
return f[x][0];
}
}dlca;
ll q(int x, int y)
{
int lca=dlca.q(x,y), K, p, d;
ll ans(0);
LinearBasis lb; lb.clear();
d=dlca.depth[x]-dlca.depth[lca]+1;
K=log2(d);
lb.insert(dlca.lb[x][K].b,59);
for(auto k(maxk);~k;k--)if( d-(1<<K) & (1<<k) )x=dlca.f[x][k];
lb.insert(dlca.lb[x][K].b,59);
d=dlca.depth[y]-dlca.depth[lca]+1;
K=log2(d);
lb.insert(dlca.lb[y][K].b,59);
for(auto k(maxk);~k;k--)if( d-(1<<K) & (1<<k) )y=dlca.f[y][k];
lb.insert(dlca.lb[y][K].b,59);
for(auto k(59);~k;k--)if( (ans&(1ll<<k))==0 )ans^=lb.b[k];
return ans;
}
void init()
{
ll i, u ,v;
N=read(); Q=read();
for(i=1;i<=N;i++)g[i]=read();
for(i=1;i<N;i++)u=read(), v=read(), G.adde(u,v,0), G.adde(v,u,0);
dlca.clear();
dlca.run(G,1);
}
int main()
{
init();
while(Q--)
{
auto x=read(), y=read();
printf("%lld\n",q(x,y));
}
return 0;
}