4568: [Scoi2016]幸运数字

Time Limit: 60 Sec  Memory Limit: 256 MB
Submit: 238  Solved: 113
[Submit][Status][Discuss]

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

HINT

Source

Solution

树上线性基

感觉可以有多重做法(1)树链剖分+线性基合并(2)LCA+倍增+线性基合并(3)点分治+线性基合并

后两个是$logn$级的,第一种是$log^{2}n$级的,自己一开始算错了复杂度,于是开心的写了(1),不过BZOJ开到60s时限,所以还是可以水过的

大体上就是树链剖分一下,线段树维护区间线性基,两个叶节点的线性基合并起来就是根的线性基,具体的合并,就是直接暴力把一个插入到另一个里面

然后查询的时候正常的查询就好了.

LCA+倍增的做法就是倍增预处理出$2^{j}$步的线性基,预处理和查询的时候,同样都是暴力合并线性基

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstring>
using namespace std;
long long read()
{
long long x=,f=; char ch=getchar();
while (ch<'' || ch>'') {if (ch=='-') f=-; ch=getchar();}
while (ch>='' && ch<='') {x=x*+ch-''; ch=getchar();}
return x*f;
}
#define maxn 20010
int n,q; long long val[maxn];
struct EdgeNode{int next,to;}edge[maxn<<];
int head[maxn],cnt;
void add(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
void insert(int u,int v) {add(u,v); add(v,u);}
//==============================================================================================
int size[maxn],deep[maxn],fa[maxn],son[maxn],pl[maxn],sz,pr[maxn],top[maxn];long long pre[maxn];
void dfs_1(int now)
{
size[now]=;
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=fa[now])
{
deep[edge[i].to]=deep[now]+;
fa[edge[i].to]=now;
dfs_1(edge[i].to);
if (size[edge[i].to]>size[son[now]]) son[now]=edge[i].to;
size[now]+=size[edge[i].to];
}
}
void dfs_2(int now,int chain)
{
pl[now]=++sz; pre[sz]=val[now]; top[now]=chain;
if (son[now]) dfs_2(son[now],chain);
for (int i=head[now]; i; i=edge[i].next)
if (edge[i].to!=fa[now] && edge[i].to!=son[now])
dfs_2(edge[i].to,edge[i].to);
pr[now]=sz;
}
//==============================================================================================
struct XXJ{long long a[];}Ans;
struct TreeNode{int l,r;XXJ X;}tree[maxn<<];
void Merge(XXJ &x,XXJ &y,XXJ &z)
{
XXJ tmp;
for (int i=; i>=; i--) tmp.a[i]=y.a[i];
for (int i=; i>=; i--)
if (z.a[i])
{
long long tp=z.a[i];
for (int i=; i>=; i--)
if (tp&(1LL<<i))
if (!tmp.a[i]) {tmp.a[i]=tp; break;}
else tp^=tmp.a[i];
}
for (int i=; i>=; i--) x.a[i]=tmp.a[i];
}
void BuildTree(int now,int l,int r)
{
tree[now].l=l; tree[now].r=r;
if (l==r)
{
memset(tree[now].X.a,0LL,sizeof(tree[now].X.a));
long long tp=pre[l];
for (int i=; i>=; i--)
if (tp&(1LL<<i))
if (!tree[now].X.a[i]) {tree[now].X.a[i]=tp; break;}
else tp^=tree[now].X.a[i];
return;
}
int mid=(l+r)>>;
BuildTree(now<<,l,mid); BuildTree(now<<|,mid+,r);
Merge(tree[now].X,tree[now<<].X,tree[now<<|].X);
}
void Query(int now,int L,int R)
{
if (L<=tree[now].l && R>=tree[now].r) {Merge(Ans,Ans,tree[now].X); return;}
int mid=(tree[now].l+tree[now].r)>>;
if (L<=mid) Query(now<<,L,R);
if (R>mid) Query(now<<|,L,R);
}
//==============================================================================================
void Solve_Query(int x,int y)
{
while (top[x]!=top[y])
{
if (deep[top[x]]<deep[top[y]]) swap(x,y);
Query(,pl[top[x]],pl[x]);
x=fa[top[x]];
}
if (deep[x]>deep[y]) swap(x,y);
Query(,pl[x],pl[y]);
}
//==============================================================================================
int main()
{
n=read();q=read();
for (int i=; i<=n; i++) val[i]=read();
for (int u,v,i=; i<=n-; i++) u=read(),v=read(),insert(u,v);
dfs_1(); dfs_2(,); BuildTree(,,n);
while (q--)
{
int x=read(),y=read(); long long ans=;
memset(Ans.a,0LL,sizeof(Ans.a));
Solve_Query(x,y);
for (int i=; i>=; i--) if ((ans^Ans.a[i])>ans) ans^=Ans.a[i];
printf("%lld\n",ans);
}
return ;
}

谢谢YJQ大大的数据,考前A题的快感

【BZOJ-4568】幸运数字 树链剖分 + 线性基合并的更多相关文章

  1. [SCOI2016]幸运数字 树链剖分,线性基

    [SCOI2016]幸运数字 LG传送门 为了快乐,我们用树剖写这题. 强行树剖,线段树上每个结点维护一个线性基,每次查询暴力合并. 瞎分析一波复杂度:树剖两点之间\(\log n\)条重链,每条重链 ...

  2. 「洛谷3292」「BZOJ4568」「SCOI2016」幸运数字【倍增LCA+线性基+合并】

    [bzoj数据下载地址]不要谢我 先讲一下窝是怎么错的... \(MLE\)是因为数组开小了.. 看到异或和最大,那么就会想到用线性基. 如果不会线性基的可以参考一下我的学习笔记:「线性基」学习笔记a ...

  3. 【CodeChef EDGEST】Edges in Spanning Trees(树链剖分+树上启发式合并)

    点此看题面 大致题意: 给你两棵\(n\)个点的树,对于第一棵树中的每条边\(e_1\),求存在多少条第二棵树中的边\(e_2\),使得第一棵树删掉\(e_1\)加上\(e_2\).第二棵树删掉\(e ...

  4. BZOJ 3531 [Sdoi2014]旅行 树链剖分+动态开点线段树

    题意 S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,满足从一个城市出发可以到达其它所有城市.每个城市信仰不同的宗教,如飞天面条神教.隐形独角兽教.绝地教都是常见的信仰. 为了方便,我们用 ...

  5. BZOJ 3531: [Sdoi2014]旅行 [树链剖分]

    3531: [Sdoi2014]旅行 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1685  Solved: 751[Submit][Status] ...

  6. BZOJ 2243: [SDOI2011]染色 [树链剖分]

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6651  Solved: 2432[Submit][Status ...

  7. [BZOJ - 2819] Nim 【树链剖分 / DFS序】

    题目链接: BZOJ - 2819 题目分析 我们知道,单纯的 Nim 的必胜状态是,各堆石子的数量异或和不为 0 .那么这道题其实就是要求求出树上的两点之间的路径的异或和.要求支持单点修改. 方法一 ...

  8. BZOJ.4515.[SDOI2016]游戏(树链剖分 李超线段树)

    BZOJ 洛谷 每次在路径上加的数是个一次函数,容易看出是树剖+李超线段树维护函数最小值.所以其实依旧是模板题. 横坐标自然是取个确定的距离标准.取每个点到根节点的距离\(dis[i]\)作为\(i\ ...

  9. bzoj 4448 [Scoi2015]情报传递 (树链剖分+主席树)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=4448 题面: Description 奈特公司是一个巨大的情报公司,它有着庞大的情报网络 ...

随机推荐

  1. 清北学堂2017NOIP冬令营入学测试P4749 C’s problem(c)

    P4746 C's problem(c) 时间: 1000ms / 空间: 655360KiB / Java类名: Main 背景 冬令营入学测试 描述 题目描述 小C是一名数学家,由于它自制力比较差 ...

  2. perl 下使用非root用户安装模块

    perl下安装模块可以使用cpan命令,但是通常我们不具有root用户权限,所以只能以sudo方式安装模块. 例如需要安装Net::SCP::Expect模块, 执行cpan Net::SCP::Ex ...

  3. TopCoder

    在TopCoder下载好luncher,网址:https://www.topcoder.com/community/competitive%20programming/ 选择launch web ar ...

  4. 求解区间最值 - RMQ - ST 算法介绍

    解析 ST 算法是 RMQ(Range Minimum/Maximum Query)中一个很经典的算法,它天生用来求得一个区间的最值,但却不能维护最值,也就是说,过程中不能改变区间中的某个元素的值.O ...

  5. Linux vmstat命令实战详解

    vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况.这个命令是我查看Linux/Unix最 ...

  6. [BZOJ3714][PA2014]Kuglarz(MST)

    题目: Description 魔术师的桌子上有n个杯子排成一行,编号为1,2,…,n,其中某些杯子底下藏有一个小球,如果你准确地猜出是哪些杯子,你就可以获得奖品.花费c_ij元,魔术师就会告诉你杯子 ...

  7. C程序两则

    <span style="font-size:24px;">#include<iostream> using namespace std; int *fun ...

  8. RabbitMQ官方中文入门教程(PHP版) 第一部分:Hello World

    RabbitMQ是一个消息代理.它的核心原理非常简单:接收和发送消息.你可以把它想像成一个邮局:你把信件放入邮箱,邮递员就会把信件投递到你的收件人处.在这个比喻中,RabbitMQ是一个邮箱.邮局.邮 ...

  9. jq不包含某属性

    jq解释属性选择器时有以下四种: 上面都是带某属性或者属性为某值的情况,还有一种情况是不带某属性怎么办? 答案是同属性不为某值. 如 <a b='c' class="d"&g ...

  10. Visual Studio 2013启用AnkSVN

    1. 官网下载AnkSVN  https://ankhsvn.open.collab.net/ 2. 安装 3. 启用 When you enable AnkhSVN as a VS.NET sour ...