zoukankan      html  css  js  c++  java
  • 【BZOJ4568】[Scoi2016]幸运数字 倍增+线性基

    【BZOJ4568】[Scoi2016]幸运数字

    Description

    A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一。每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征。一些旅行者希望游览 A 国。旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国。在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上。然而,幸运是不能简单叠加的,这一点游览者也十分清楚。他们迷信着幸运数字是以异或的方式保留在自己身上的。例如,游览者拍了 3 张照片,幸运值分别是 5,7,11,那么最终保留在自己身上的幸运值就是 9(5 xor 7 xor 11)。有些聪明的游览者发现,只要选择性地进行拍照,便能获得更大的幸运值。例如在上述三个幸运值中,只选择 5 和 11 ,可以保留的幸运值为 14 。现在,一些游览者找到了聪明的你,希望你帮他们计算出在他们的行程安排中可以保留的最大幸运值是多少。

    Input

    第一行包含 2 个正整数 n ,q,分别表示城市的数量和旅行者数量。第二行包含 n 个非负整数,其中第 i 个整数 Gi 表示 i 号城市的幸运值。随后 n-1 行,每行包含两个正整数 x ,y,表示 x 号城市和 y 号城市之间有一条道路相连。随后 q 行,每行包含两个正整数 x ,y,表示这名旅行者的旅行计划是从 x 号城市到 y 号城市。N<=20000,Q<=200000,Gi<=2^60

    Output

     输出需要包含 q 行,每行包含 1 个非负整数,表示这名旅行者可以保留的最大幸运值。

    Sample Input

    4 2
    11 5 7 9
    1 2
    1 3
    1 4
    2 3
    1 4

    Sample Output

    14
    11

    题解:求LCA可以用倍增,同时,我们还可以维护f[i][j]表示从i往上的2j个点中,所有权值的线性基。然后查询的时候我们把路径上的线性基都拿出来一起消一下,贪心求最大值就行了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    const int maxn=20005;
    typedef long long ll;
    int n,m,cnt;
    int fa[15][maxn],dep[maxn],to[maxn<<1],next[maxn<<1],head[maxn];
    struct node
    {
    	int siz;
    	ll v[61];
    	node (){memset(v,0,sizeof(v)),siz=0;}
    	ll gauss(ll x)
    	{
    		int i;
    		for(i=0;i<siz;i++)	if((v[i]^x)<x)	x^=v[i];
    		if(x)
    		{
    			v[siz++]=x;
    			for(i=siz-1;i;i--)	if(v[i-1]<v[i])	swap(v[i-1],v[i]);
    		}
    		return x;
    	}
    	ll query()
    	{
    		ll ret=0;
    		for(int i=0;i<siz;i++)	if((ret^v[i])>ret)	ret^=v[i];
    		return ret;
    	}
    }s[15][maxn];
    ll rd()
    {
    	ll ret=0;	char gc=getchar();
    	while(gc<'0'||gc>'9')	gc=getchar();
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret;
    }
    void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    void dfs(int x)
    {
    	for(int i=head[x];i!=-1;i=next[i])
    		if(to[i]!=fa[0][x])
    			fa[0][to[i]]=x,dep[to[i]]=dep[x]+1,dfs(to[i]);
    }
    int main()
    {
    	//freopen("bz4568.in","r",stdin);
    	n=rd(),m=rd();
    	int i,j,k,a,b;
    	for(i=1;i<=n;i++)	s[0][i].gauss(rd());
    	memset(head,-1,sizeof(head));
    	for(i=1;i<n;i++)	a=rd(),b=rd(),add(a,b),add(b,a);
    	dep[1]=1,dfs(1);
    	for(j=1;(1<<j)<=n;j++)
    	{
    		for(i=1;i<=n;i++)
    		{
    			for(k=0;k<s[j-1][i].siz;k++)	s[j][i].gauss(s[j-1][i].v[k]);
    			for(k=0;k<s[j-1][fa[j-1][i]].siz;k++)	s[j][i].gauss(s[j-1][fa[j-1][i]].v[k]);
    			fa[j][i]=fa[j-1][fa[j-1][i]];
    		}
    	}
    	for(i=1;i<=m;i++)
    	{
    		a=rd(),b=rd();
    		node ans;
    		if(dep[a]<dep[b])	swap(a,b);
    		for(j=14;j>=0;j--)
    		{
    			if(dep[fa[j][a]]>=dep[b])
    			{
    				for(k=0;k<s[j][a].siz;k++)	ans.gauss(s[j][a].v[k]);
    				a=fa[j][a];
    			}
    		}
    		if(a!=b)
    		{
    			for(j=14;j>=0;j--)
    			{
    				if(fa[j][a]!=fa[j][b])
    				{
    					for(k=0;k<s[j][a].siz;k++)	ans.gauss(s[j][a].v[k]);
    					for(k=0;k<s[j][b].siz;k++)	ans.gauss(s[j][b].v[k]);
    					a=fa[j][a],b=fa[j][b];
    				}
    			}
    			ans.gauss(s[0][a].v[0]),ans.gauss(s[0][b].v[0]),ans.gauss(s[0][fa[0][a]].v[0]);
    		}
    		else	ans.gauss(s[0][a].v[0]);
    		printf("%lld
    ",ans.query());
    	}
    	return 0;
    }
  • 相关阅读:
    iOS开发之Masonry框架源码解析
    iOS开发针对对Masonry下的FPS优化讨论
    React-native Android环境搭建
    Android中ListView使用总结
    Android开发布局方式
    轮播图
    大文件断点下载
    基于第三方库FMDB的数据库的二次封装
    md5加密
    AssignToObject文件(字典转模型、字典数组转模型数组)
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7150418.html
Copyright © 2011-2022 走看看