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/+

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

原文地址:https://www.cnblogs.com/luyouqi233/p/8822674.html

时间: 2024-10-08 18:38:17

BZOJ4568:[SCOI2016]幸运数字——题解的相关文章

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

4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 2131  Solved: 865[Submit][Status][Discuss] Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划 乘飞机降落在 x 号城市,沿着 x

bzoj4568 [Scoi2016]幸运数字

Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国.在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上.然而,幸运是不能简单叠加的,这一点游览者也十分清楚.他们迷

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

洛谷T了,mmp 还是bzoj时限良心,虽然三天两头爆炸 算是简单的题吧,构造出每个点logn个的线性基表 感觉线性基最nb的就是只有log个,所以可以做的很暴力 合并就是拆开再并 1 #include <bits/stdc++.h> 2 using namespace std; 3 struct Bas 4 { 5 long long a[61]; 6 Bas() 7 { 8 for(int i=0;i<=60;i++) 9 a[i]=0; 10 } 11 void add(long

bzoj 4568: [Scoi2016]幸运数字

4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 848  Solved: 336[Submit][Status][Discuss] Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划 乘飞机降落在 x 号城市,沿着 x 号

【BZOJ-4568】幸运数字 树链剖分 + 线性基合并

4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 238  Solved: 113[Submit][Status][Discuss] Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划乘飞机降落在 x 号城市,沿着 x 号城市

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

4568: [Scoi2016]幸运数字 Description A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A 国.旅行者计划 乘飞机降落在 x 号城市,沿着 x 号城市到 y 号城市之间那条唯一的路径游览,最终从 y 城市起飞离开 A 国. 在经过每一座城市时,游览者就会有机会与这座城市的幸运数字拍照,从而将这份幸运保存到自己身上.然而,幸

[SCOI2016]幸运数字 线性基

题面 题面 题解 题面意思非常明确:求树上一条链的最大异或和. 我们用倍增的思想. 将这条链分成2部分:x ---> lca , lca ---> y 分别求出这2个部分的线性基,然后合并,再求最大异或和. 所以我们现在只需要考虑如何在树上求一条无需拐弯的链的最大线性基. 考虑倍增. 我们预处理出f[i][j]表示从点i开始向上走\(2^j\)构成的链的线性基.至于只有点\(i\)一个点的线性基,我们可以在运算的时候特判一下处理. 暴力预处理后,我们就可以最多 合并3次 + 求LCA的复杂度

SCOI2016 幸运数字

传送门 如果只是一条路径的话,那就是非常简单的线性基. 不过要考虑多组询问-- 考虑到n比较小,我们可以模仿倍增LCA的方法,预处理倍增的线性基.在每次路径上跳的时候把线性基合并最后求解即可.具体的做法是,我们用\(p[i][x][j]\)表示在编号为x的点处,向上跳\(2^i\)步以内,线性基第j位的数.这个可以合并,比较好写的方法就是直接传两个数组进去合并. 之后就正常了.代码很短,不到100行.(我交了好多次因为忘记用longlong快读了--) #include<iostream> #

luoguP3292 [SCOI2016]幸运数字(线性基+树上倍增)

传送:https://www.luogu.org/problem/P3292 题意: $n$座城市,$n-1$条路,每个城市有一个价值$a_i$.$q$个询问,每次询问城市$x$到城市$y$的路径上经过的城市的价值的最大异或和为多少. 数据范围: $1<=n<=20000,q<=200000,a_i<=2^{60}$. 分析: 对于一次询问$x-->y$的路径上的答案,很明显就是$x-->lca(x,y)$的线性基并上$y-->lca(x,y)$的线性基,然后求最