标签:
一棵
有
对于小数据我们可以想到一种高斯消元解异或方程组的解法。从高位到低位,先假设当前位有
但是满分数据很大,这样做是不行的。这里我们就要用到一种叫做线性基的强大的东西。我们先来看看什么叫线性基:
啊不~不是这个(这么说我就是神犇了?哈哈哈哈哈~~~)。
线性基是什么呢?就是给定一个二进制集合
说白了就是高斯消元解异或方程组最后剩下的矩阵。
换句话说利用线性基内的互相异或,就可以得出原集合互相异或的结果。如果二进制位数为
可以证明,线性基内不存在异或和为
我们采用
那么我们查询最大异或和时可以直接从高位到低位贪心,如果异或上线性基第
线性基的合并就是和高斯消元差不多,对于第二个线性基的每一个待插入数,我们枚举第一个线性基里的位置
设二进制有
回到这题,使用倍增维护树上区间的线性基,暴力合并即可。
注意到这里合并线性基的复杂度很大,如果合并多次是很难承受的。因此这里我们要使用类
总时间复杂度
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
#include <cmath>
using namespace std;
typedef long long LL;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch==‘-‘?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-‘0‘,ch=getchar();
return x*f;
}
const int N=20050;
const int M=N<<1;
const int LGN=15;
const int D=60;
struct linear_basic
{
LL num[D];
};
typedef linear_basic LB;
LB operator+(LB x,LB y)
{
for (int i=D-1;i>=0;i--)
if (y.num[i])
for (int j=D-1;j>=0;j--)
{
if (!y.num[i]) break;
if (y.num[i]>>j&1)
if (x.num[j]) y.num[i]^=x.num[j];
else
{
x.num[j]=y.num[i];
break;
}
}
return x;
}
int last[N],high[N];
int tov[M],next[M];
int n,lgn,tot,q;
int fa[N][LGN];
LB f[N][LGN];
void insert(int x,int y){tov[++tot]=y,next[tot]=last[x],last[x]=tot;}
void dfs(int x)
{
for (int i=last[x],y;i;i=next[i])
if ((y=tov[i])!=fa[x][0])
fa[y][0]=x,high[y]=high[x]+1,dfs(y);
}
void pre()
{
lgn=trunc(log(n)/log(2));
for (int j=1;j<=lgn;j++)
for (int i=1;i<=n;i++)
fa[i][j]=fa[fa[i][j-1]][j-1],f[i][j]=f[i][j-1]+f[fa[i][j-1]][j-1];
}
int lca(int x,int y)
{
if (high[x]>high[y]) swap(x,y);
for (int i=lgn;i>=0;i--)
if (high[fa[y][i]]>=high[x]) y=fa[y][i];
if (x==y) return x;
for (int i=lgn;i>=0;i--)
if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int p(int x,int h)
{
for (int i=lgn;i>=0;i--)
if (high[fa[x][i]]>=h) x=fa[x][i];
return x;
}
LL query(int x,int y)
{
int z=lca(x,y);
int lgh;
lgh=trunc(log(high[x]-high[z]+1)/log(2));
LB lb0=f[x][lgh]+f[p(x,high[z]+(1<<lgh)-1)][lgh];
lgh=trunc(log(high[y]-high[z]+1)/log(2));
lb0=lb0+f[y][lgh]+f[p(y,high[z]+(1<<lgh)-1)][lgh];
LL ret=0;
for (int i=D-1;i>=0;i--) if ((ret^lb0.num[i])>ret) ret^=lb0.num[i];
return ret;
}
int main()
{
freopen("lucky.in","r",stdin),freopen("lucky.out","w",stdout);
n=read(),q=read();
for (int i=1;i<=n;i++)
{
LL x;
scanf("%lld",&x);
for (int j=D-1;j>=0;j--)
if (x>>j&1)
{
f[i][0].num[j]=x;
break;
}
}
for (int i=1,x,y;i<n;i++)
{
x=read(),y=read();
insert(x,y),insert(y,x);
}
dfs(1),pre();
for (int i=1,x,y;i<=q;i++)
{
x=read(),y=read();
printf("%lld\n",query(x,y));
}
fclose(stdin),fclose(stdout);
return 0;
}
标签:
原文地址:http://blog.csdn.net/a_crazy_czy/article/details/51921324