[SCOI2016]幸运数字

题目

来写一个\(3\)\(log\)的垃圾做法

其实非常显然就是倍增把这条路径处理一遍,之后维护出倍增数组的线性基,大力合并就好了

线性基合并就是把一个线性基的所有元素都拿出来,一个一个插入到另外一个中去

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 20005
#define re register
#define LL long long
inline LL read() {
	LL x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();
	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt;}e[maxn<<1];
int f[maxn][17];
LL a[maxn],lb[maxn][17][66];
int log_2[maxn],deep[maxn],head[maxn];
int n,num,Q;
inline void add(int x,int y) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;}
void dfs(int x) {
	for(re int i=head[x];i;i=e[i].nxt) 
	if(!deep[e[i].v]) {
		deep[e[i].v]=deep[x]+1;f[e[i].v][0]=x;
		dfs(e[i].v);
	}
}
inline void ins(LL x,int t,int b) {
	for(re int j=61;j>=0;--j)
	if(x>>j&1ll) {
		if(!lb[t][b][j]) {lb[t][b][j]=x;return;}
		x^=lb[t][b][j];
	}
}
inline void merge(int x,int y,int c,int d) {
	for(re int t=61;t>=0;--t) {
		if(!lb[c][d][t]) continue;
		ins(lb[c][d][t],x,y);
	}
}
inline void solve(int x,int y) {
	memset(lb[0][0],0,sizeof(lb[0][0]));
	if(x==y) {ins(a[x],0,0);return;}
	if(deep[x]<deep[y]) std::swap(x,y);
	for(re int i=log_2[deep[x]];i>=0;--i) 
	if(f[x][i]&&deep[f[x][i]]>=deep[y]) 
		merge(0,0,x,i),x=f[x][i];
	if(x==y) return;
	for(re int i=log_2[deep[x]];i>=0;--i) 
	if(f[x][i]!=f[y][i]) {
		merge(0,0,x,i),merge(0,0,y,i);
		x=f[x][i],y=f[y][i];
	}
	ins(a[x],0,0),ins(a[y],0,0);if(f[x][0])ins(a[f[x][0]],0,0);
}
int main()
{
	n=read(),Q=read();
	for(re int i=1;i<=n;i++) a[i]=read();
	int x,y;
	for(re int i=1;i<n;i++) x=read(),y=read(),add(x,y),add(y,x);
	deep[1]=1;dfs(1);
	for(re int i=2;i<=n;i++) log_2[i]=log_2[i>>1]+1;
	for(re int i=1;i<=n;i++) ins(a[i],i,0);
	for(re int i=1;i<=n;i++) if(f[i][0]) ins(a[f[i][0]],i,0);
	for(re int j=1;j<=log_2[n];j++)
		for(re int i=1;i<=n;i++) {
			if(!f[i][j-1]) continue;
			f[i][j]=f[f[i][j-1]][j-1];
			merge(i,j,i,j-1);merge(i,j,f[i][j-1],j-1);
		}
	while(Q--) {
		x=read(),y=read();
		solve(x,y);
		LL ans=0;
		for(re int i=61;i>=0;--i) if((ans^lb[0][0][i])>ans) ans^=lb[0][0][i];
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2019-02-16 21:19  asuldb  阅读(183)  评论(0编辑  收藏  举报