bzoj 4568 幸运数字【线性基】
2016-07-11 19:20
246 查看
题目大意:给定一棵树,求路径的最大异或和。
倍增 + 线性基
线性基暴力合并…
没什么说的…
怪我太弱了,省选的时候还不会,然后gg,现在才学…orz
倍增 + 线性基
线性基暴力合并…
没什么说的…
怪我太弱了,省选的时候还不会,然后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; }
相关文章推荐