幸运数字(luckly)

幸运数字(luckly)

题目描述

A国共有 nn 座城市,这些城市由

TeX parse error: Misplaced &
条道路相连,使得任意两座城市可以互达,且路径唯一。每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征。

一些旅行者希望游览A国。旅行者计划乘飞机降落在 xx 号城市,沿着 xx 号城市到 yy 号城市之间那条唯一的路径游览,最终从 yy 城市起飞离开A国。在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上。

然而,幸运是不能简单叠加的,这一点游览者也十分清楚。他们迷信着幸运数字是以异或的方式保留在自己身上的。例如,游览者拍了 33 张照片,幸运值分别是 5,7,115,7,11 ,那么最终保留在自己身上的幸运值就是 9(5 \ xor \ 7 \ xor \ 11)9(5 xor 7 xor 11) 。有些聪明的游览者发现,只要选择性地进行拍照,便能获得更大的幸运值。例如在上述三个幸运值中,只选择 55 和 1111 ,可以保留的幸运值为 1414 。

现在,一些游览者找到了聪明的你,希望你帮他们计算出在他们的行程安排中可以保留的最大幸运值是多少。

输入格式

第一行包含 22 个正整数 nn 、 qq ,分别表示城市的数量和旅行者数量。

第二行包含 nn 个非负整数,其中第 ii 个整数 G_iGi 表示 ii 号城市的幸运值。

随后

TeX parse error: Misplaced &
行,每行包含两个正整数  xx 、 yy ,表示 xx 号城市和 yy 号城市之间有一条道路相连。

随后 qq 行,每行包含两个正整数 xx 、 yy ,表示这名旅行者的旅行计划是从 xx 号城市到 yy 号城市。

输出格式

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

 

样例

样例输入

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

样例输出

14
11

数据范围与提示

【数据范围】

来源

SCOI2016 Day1

solution
看到求最大异或和,考虑用线性基解决。
我们开一个线性基的倍增数组。跳lca即可。
树剖+线段树可以支持修改。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define ll long long
#define maxn 20005
using namespace std;
int n,q,f[maxn][22],deep[maxn],head[maxn],tot;
ll a[maxn];
struct node{
    int v,nex;
}e[maxn*2];
struct xx{
    ll s[63];
    void ins(ll k){
        for(int i=62;i>=0;i--){
            if(k&(1LL<<i)){
                if(!s[i]){s[i]=k;break;}
                k^=s[i];
            }
        }
    }
    void c(){
        memset(s,0,sizeof s);
    }
}g[maxn][22];
void lj(int t1,int t2){
    e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void dfs(int k,int fa){
    f[k][0]=fa;g[k][0].ins(a[k]);deep[k]=deep[fa]+1;
    for(int i=head[k];i;i=e[i].nex){
        if(e[i].v==fa)continue;
        dfs(e[i].v,k);
    }
}
xx merge(xx A,xx B){
    for(int i=62;i>=0;i--){
        if(B.s[i]>0)A.ins(B.s[i]);
    }
    return A;
}
ll work(int t1,int t2){
    xx ans;ans.c();
    if(deep[t1]<deep[t2])swap(t1,t2);
    for(int x=20;x>=0;x--){
        if(deep[f[t1][x]]>=deep[t2])ans=merge(ans,g[t1][x]),t1=f[t1][x];
    }
    for(int x=20;x>=0;x--){
        if(f[t1][x]!=f[t2][x]){
            ans=merge(ans,g[t1][x]),t1=f[t1][x];
            ans=merge(ans,g[t2][x]),t2=f[t2][x];
        }
    }
    if(t1!=t2)ans=merge(ans,g[t1][0]),ans=merge(ans,g[t2][0]),t1=f[t1][0];
    ans=merge(ans,g[t1][0]);
    ll A=0;
    for(int i=62;i>=0;i--)A=max(A,A^ans.s[i]);
    return A;
}
int main()
{
    cin>>n>>q;
    for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
    for(int i=1,t1,t2;i<n;i++){
        scanf("%d%d",&t1,&t2);
        lj(t1,t2);lj(t2,t1);
    }
    dfs(1,0);
    for(int j=1;j<=20;j++)
    for(int i=1;i<=n;i++){
        f[i][j]=f[f[i][j-1]][j-1];
        g[i][j]=merge(g[i][j-1],g[f[i][j-1]][j-1]);
    }
    for(int i=1,t1,t2;i<=q;i++){
        scanf("%d%d",&t1,&t2);
        printf("%lld\n",work(t1,t2));
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/liankewei/p/10518883.html