[2018.12.28]BZOJ4568 [Scoi2016]幸运数字

这种异或和问题一看就是线性基对吧。。。

要维护的是树上两点之间的路径,所以考虑倍增。

发现可以记\(p_{i,j}\)\(i\)\(i\)\(2^j\)次父亲(不含)的点权构出的线性基。

于是我们需要合并两个线性基,记这个操作为\(Merge(p1,p2)\)

\(p_{i,j}=Merge(p_{i,j-1},P_{f_{i,j-1},j-1})\)

如何实现?

其实很简单,枚举其中一个线性基中的元素,按照之前构建线性基的方法加入另一个线性基即可。

然后...做完了?!

时间复杂度\(O(qlog^2a_ilogn)\),而且读入/输出的数字规模较大,消耗的时间较多,所以你需要读优。

可能还需要氧气

code:

#include<bits/stdc++.h>
using namespace std;
int n,q,u,v,vis[20010],f[20010][20],dep[20010],pr[20],sz;
long long g[20010],p[20010][20][65],P[65],ans;
vector<int>e[20010];
void scan(long long &x){
	char c=getchar();
	x=0;
	while('0'>c||c>'9')c=getchar();
	while('0'<=c&&c<='9')x=x*10+c-'0',c=getchar();
}
void scan(int &x){
	char c=getchar();
	x=0;
	while('0'>c||c>'9')c=getchar();
	while('0'<=c&&c<='9')x=x*10+c-'0',c=getchar();
}
void print(long long x){
	sz=0;
	while(x)pr[++sz]=x%10,x/=10;
	while(sz)putchar(pr[sz--]+'0');
}
void Push(long long x,long long *pp){
	if(!x)return;
	for(int i=60;i>=0;i--){
		if(x&(1ll<<i)){
			if(!pp[i])pp[i]=x;
			x^=pp[i];
		}
	}
}
void Merge1(long long *p1,long long *p2,long long *mp){
	for(int i=60;i>=0;i--)mp[i]=p1[i];
	for(int i=60;i>=0;i--)Push(p2[i],mp);
}
void Merge2(long long *p1,long long *mp){
	for(int i=60;i>=0;i--)Push(p1[i],mp);
}
void dfs(int x){
	vis[x]=1;
	for(int i=0;i<e[x].size();i++)
		if(!vis[e[x][i]])dep[e[x][i]]=dep[x]+1,dfs(e[x][i]);
		else f[x][0]=e[x][i];
}
void LCA_GetP(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	for(int i=15;i>=0;i--)if(dep[x]-(1<<i)>=dep[y])Merge2(p[x][i],P),x=f[x][i];
	for(int i=15;i>=0;i--)if(f[x][i]!=f[y][i])Merge2(p[x][i],P),x=f[x][i],Merge2(p[y][i],P),y=f[y][i];
	if(x!=y)Push(g[x],P),Push(g[y],P),Push(g[f[x][0]],P);
	else Push(g[x],P);
}
int main(){
	scan(n),scan(q);
	for(int i=1;i<=n;i++)scan(g[i]),Push(g[i],p[i][0]);
	for(int i=1;i<n;i++)scan(u),scan(v),e[u].push_back(v),e[v].push_back(u);
	dep[1]=1;
	dfs(1);
	for(int j=1;j<=15;j++)for(int i=1;i<=n;i++)Merge1(p[i][j-1],p[f[i][j-1]][j-1],p[i][j]),f[i][j]=f[f[i][j-1]][j-1];
	while(q--){
		scan(u),scan(v);
		memset(P,0ll,sizeof(P));
		ans=0;
		LCA_GetP(u,v);
		for(int i=60;i>=0;i--)(ans^P[i])>ans?ans^=P[i]:0;
		print(ans),putchar('\n');
	}
	return 0;
}
posted @ 2019-03-15 15:49  xryjr233  阅读(118)  评论(0编辑  收藏  举报