BZOJ 4568 [Scoi2016]幸运数字 ——线性基 倍增

【题目分析】

    考虑异或的最大值,维护线性基就可以了。

    但是有多次的询问,树剖或者倍增都可以。

    想了想树剖动辄数百行的代码。

    算了,我还是写倍增吧。

    注:被位运算和大于号的优先级坑了一次,QaQ

【代码】

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>

#include <set>
#include <map>
#include <string>
#include <algorithm>
#include <vector>
#include <iostream>
#include <queue>

using namespace std;

#define ll long long 
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define maxn 20005
#define mlog 20
#define mxle 64
#define mxed 50005

int Getint()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

ll Getll()
{
    ll x=0,f=1; char ch=getchar();
    while (ch<'0'||ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}

void Finout()
{
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    #endif
}

struct Base{
	ll lb[mxle];
	void add(ll x)
	{
		D(i,63,0)
		{
			if ((x>>i)&1)
			{
				if (!lb[i]) {lb[i]=x;break;}
				else x^=lb[i];
			}
		}
	}
	void init(ll x){memset(lb,0,sizeof lb);add(x);}
};

Base add(Base x,Base y)
{
	Base ret=x;
	F(i,0,63) if (y.lb[i]) ret.add(y.lb[i]);
	return ret;
}

int f[maxn][mlog],n,q,h[mxed],to[mxed],ne[mxed],en=0,dst[maxn];
Base g[maxn][mlog];

void add(int a,int b)
{
	to[en]=b; ne[en]=h[a]; h[a]=en++;
	to[en]=a; ne[en]=h[b]; h[b]=en++;
}

void dfs(int o)
{
	for (int i=h[o];i>=0;i=ne[i])
		if (f[o][0]!=to[i])
		{
			f[to[i]][0]=o;
			dst[to[i]]=dst[o]+1;
			dfs(to[i]);
		}
}

ll query(Base x)
{
	ll sum=0;
	D(i,63,0)
	if ((x.lb[i]^sum)>sum) sum^=x.lb[i];
	return sum;
}

ll ask(int a,int b)
{
	if (dst[a]<dst[b]) swap(a,b);
	Base ret;ret.init(0);
	int dist=dst[a]-dst[b];
	D(i,mlog-1,0)
		if ((dist>>i)&1)
		{
			ret=add(ret,g[a][i]);
			a=f[a][i];
		}
	if (a==b)
	{
		ret=add(ret,g[a][0]);
		return query(ret);
	}
	D(i,mlog-1,0)
		if (f[a][i]!=f[b][i])
		{
			ret=add(ret,g[a][i]);
			ret=add(ret,g[b][i]);
			a=f[a][i];b=f[b][i];
		}
	ret=add(ret,g[a][1]);
	ret=add(ret,g[b][0]);
	return query(ret);
}

int main()
{
	Finout();
	memset(h,-1,sizeof h);
	n=Getint(); q=Getint();
	F(i,1,n) g[i][0].init(Getll());
	F(i,1,n-1) add(Getint(),Getint());
	dfs(1);
	F(i,1,mlog-1)
		F(j,1,n)
		{	
			f[j][i]=f[f[j][i-1]][i-1];
			g[j][i]=add(g[j][i-1],g[f[j][i-1]][i-1]);
		}
	F(i,1,q) printf("%lld\n",ask(Getint(),Getint()));
}

  

posted @ 2017-01-26 21:35  SfailSth  阅读(206)  评论(0编辑  收藏  举报