BZOJ4568:[SCOI2016]幸运数字——题解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ4568:[SCOI2016]幸运数字——题解相关的知识,希望对你有一定的参考价值。

https://www.lydsy.com/JudgeOnline/problem.php?id=4568

https://www.luogu.org/problemnew/show/P3292

A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一。每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征。

一些旅行者希望游览 A 国。旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国。在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上。然而,幸运是不能简单叠加的,这一点游览者也十分清楚。他们迷信着幸运数字是以异或的方式保留在自己身上的。

例如,游览者拍了 3 张照片,幸运值分别是 5,7,11,那么最终保留在自己身上的幸运值就是 9(5 xor 7 xor 11)。

有些聪明的游览者发现,只要选择性地进行拍照,便能获得更大的幸运值。例如在上述三个幸运值中,只选择 5 和 11 ,可以保留的幸运值为 14 。现在,一些游览者找到了聪明的你,希望你帮他们计算出在他们的行程安排中可以保留的最大幸运值是多少。

学会了st表求线性基的方法。

我们可以将一个线性基内的东西全部扔到另一个线性基里面,就是一种合并了。

然后就没有了,LCA求顺带着合并线性基即可。

(其实实际上这是一道码农题。)

#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<cmath>
#include<cctype>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=20010;
const int BASE=60;
const int LOGN=15;
inline ll read(){
    ll X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch==\'-\';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct node{
    int to,nxt;
}e[N*2];
struct basis{
    ll c[BASE+2];
}b[N][LOGN+2];
int n,q,cnt,head[N],dep[N];
int anc[N][LOGN+2];
inline void add(int u,int v){
    e[++cnt].to=v;e[cnt].nxt=head[u];head[u]=cnt;
}
void ins(ll k,basis &a){
    for(int i=BASE;i>=0;i--)
    if(k>>i&1)
        if(a.c[i])k^=a.c[i];
        else{
        a.c[i]=k;
        break;
        }
}
basis merge(basis a,basis b){
    for(int i=BASE;i>=0;i--)
    if(b.c[i])ins(b.c[i],a);
    return a;
}
void dfs(int u){
    dep[u]=dep[anc[u][0]]+1;
    for(int i=1;i<=LOGN;i++){
    anc[u][i]=anc[anc[u][i-1]][i-1];
    b[u][i]=merge(b[u][i-1],b[anc[u][i-1]][i-1]);
    }
    for(int i=head[u];i;i=e[i].nxt){
    int v=e[i].to;
    if(v!=anc[u][0]){
        anc[v][0]=u;
        dfs(v);
    }
    }
}
ll getans(basis a){
    ll ans=0;
    for(int i=BASE;i>=0;i--)
    ans=max(ans,ans^a.c[i]);
    return ans;
}
ll query(int i,int j){
    static basis t1,t2;
    memset(t1.c,0,sizeof(t1.c));
    memset(t2.c,0,sizeof(t2.c));
    if(dep[i]<dep[j])swap(i,j);
    for(int k=LOGN;k>=0;k--){
        if(dep[anc[i][k]]>=dep[j]){
        t1=merge(t1,b[i][k]);
        i=anc[i][k];
    }
    }
    if(i==j)return getans(merge(t1,b[i][0]));
    for(int k=LOGN;k>=0;k--){
        if(anc[i][k]!=anc[j][k]){
        t1=merge(t1,b[i][k]);t2=merge(t2,b[j][k]);
        i=anc[i][k],j=anc[j][k];
    }
    }
    t1=merge(t1,b[i][0]);t2=merge(t2,b[j][0]);
    return getans(merge(merge(t1,t2),b[anc[i][0]][0]));
}
int main(){
    n=read(),q=read();
    for(int i=1;i<=n;i++)ins(read(),b[i][0]);
    for(int i=1;i<n;i++){
    int u=read(),v=read();
    add(u,v);add(v,u);
    }
    dfs(1);
    for(int i=1;i<=q;i++){
    int u=read(),v=read();
    printf("%lld\\n",query(u,v));
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

以上是关于BZOJ4568:[SCOI2016]幸运数字——题解的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 4568 4568: [Scoi2016]幸运数字 (线性基+树链剖分+线段树)

[BZOJ4568][SCOI2016]幸运数字(倍增LCA,点分治+线性基)

BZOJ4568:[SCOI2016]幸运数字——题解

bzoj4568: [Scoi2016]幸运数字(LCA+线性基)

bzoj4568 [Scoi2016]幸运数字

bzoj4568: [Scoi2016]幸运数字 线性基 倍增

(c)2006-2024 SYSTEM All Rights Reserved IT常识