鏈接
https://www.luogu.org/problemnew/show/P3292
https://ac.nowcoder.com/acm/problem/20308
做題的經過(可以跳過)
這不是樹上倍增維護線性基的裸題嗎
然而我寫了一整天
故事是這樣的:
我先寫了個自認爲的樹剖+線段樹維護區間線性基,然後了,事後發現原來這個算法的複雜度是(這不妥妥掉嗎)
然後我又寫了個真的是的倍增,誰知道洛谷機器慢的要死,還是了
然後我又寫了個的倍增,洛谷上還是,我就開始懷疑人生,結果開了就過了,還挺快…
題解
就是個裸題,樹上倍增維護線性基
查詢的時候,最直接的做法就是一邊往上跳一邊查詢,這樣複雜度是
優化可以效仿序列上的,先求,這樣我就知道了我要跳的區間的長度,這樣求出區間長度,就可以把原來的次合併線性基優化到合併次
代碼
#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;
}