您的位置:首页 > 其它

bzoj 4568 幸运数字【线性基】

2016-07-11 19:20 246 查看
题目大意:给定一棵树,求路径的最大异或和。

倍增 + 线性基

线性基暴力合并…

没什么说的…

怪我太弱了,省选的时候还不会,然后gg,现在才学…orz

#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<cstring>
#include<string>
#define N 20005
#define LL long long
using namespace std;

int n,q,siz,x,y;LL w;
int first
,next[N*2],to[N*2];
int d
,g
[16],p
;
struct node
{
LL ins[61];
void clear()
{
memset(ins,0,sizeof(ins));
}
LL cal()
{
for (int i = 0;i <= 60;i ++) if (ins[i])
for (int j = i+1;j <= 60;j ++)
if ((ins[j] >> i) & 1) ins[j] ^= ins[i];
LL ret = 0;
for (int i = 60;~i;i --)
ret = max(ret,ret ^ ins[i]);
return ret;
}

}A
[16],ans;

void inser(int x,int y)
{
next[++ siz] = first[x];
first[x] = siz;
to[siz] = y;
}

void un(node &a,node b)
{
for (int i = 0;i <= 60;i ++) if (b.ins[i])
{
LL t = b.ins[i];
for (int j = i;~j;j --)
if ((t >> j) & 1)
{
if (!a.ins[j]) {a.ins[j] = t;break;}
else t ^= a.ins[j];
}
}
}

void bfs()
{
int head = 0,tail = 1;
d[p[1] = 1] = 1;
while (head ^ tail)
{
int x = p[++ head];
for (int y,i = first[x];i;i = next[i])
if (!d[y = to[i]])
{
d[y] = d[x] + 1,g[y][0] = x;
for (int k = 0;g[y][k];k ++)
{
g[y][k + 1] = g[g[y][k]][k];
A[y][k + 1] = A[y][k],un(A[y][k + 1],A[g[y][k]][k]);
}
p[++ tail] = y;
}
}
}

void jump(int x,int y)
{
if (d[x] < d[y]) swap(x,y);
for (int i = 14;~i;i --)
if (d[g[x][i]] >= d[y])
un(ans,A[x][i]),x = g[x][i];
if (x == y) {un(ans,A[x][0]);return;}
for (int i = 14;~i;i --)
if (g[x][i] ^ g[y][i])
{
un(ans,A[x][i]),un(ans,A[y][i]);
x = g[x][i],y = g[y][i];
}
un(ans,A[x][1]),un(ans,A[y][0]);
}

int main()
{
scanf("%d%d",&n,&q);
for (int i = 1;i <= n;i ++)
{
scanf("%lld",&w);
for (int j = 60;~j;j --)
if ((w >> j) & 1) {A[i][0].ins[j] = w;break;}
}
for (int i = 1;i < n;i ++)
{
scanf("%d%d",&x,&y);
inser(x,y),inser(y,x);
}
bfs();
while (q --)
{
scanf("%d%d",&x,&y);
ans.clear();
jump(x,y);
printf("%lld\n",ans.cal());
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: