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

题解

线性基+点分治。

这两个都是最近才接触的,正好有道题结合起来了。

我们每次找到重心,处理与重心相关的路径。

处理时我们将重心到每个节点这一段的$xor$存起来,然后找到所有经过重心的路径。

我是在遍历以重心$G$为根的一个子树过程中,找到与这棵子树中节点$u$有关的询问$(u,v)$,判断是否在之前遍历过的以重心为根的其他子树中出现过,如果出现过,我们可以将$G->u$和$G->v$这两段的线性基合并。找到合并后的线性基中的最大值就好了。对于合并,直接暴力拆开一个线性基,一个一个插入到另一个线性基中。

处理完这棵子树之后,再遍历一遍,打上访问过的标记。这样保证所有询问都只计算过一次。

注意,处理完这个重心之后,清空标记时,不要$memset$,直接再遍历一遍就好了,快得多。

值得注意的是,要单独考虑与$G$有关的询问如$(G,v)$,因为重心$G$没标记访问过。(当然了,你可以找完重心后就马上把重心标记访问,效果是一样的,这个询问也只会遍历一次。因为重心是不会被访问的)

另外注意单独考虑$(u,u)$的询问。

 //It is made by Awson on 2017.9.22
#include <set>
#include <map>
#include <ctime>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define LL long long
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define sqr(x) ((x)*(x))
using namespace std;
const int N = ;
const int Q = ;
const int INF = ~0u>>;
LL st[];
int Read() {
int sum = ;
char ch = getchar();
while (ch < '' || ch > '') ch = getchar();
while (ch >= '' && ch <= '') sum = (sum<<)+(sum<<)+ch-, ch = getchar();
return sum;
} struct base {
LL a[];
void insert(LL x) {
for (int i = ; i >= ; i--)
if (x&st[i]) {
if (!a[i]) {
a[i] = x;
break;
}
else x ^= a[i];
}
}
LL getmax() {
LL maxn = ;
for (int i = ; i >= ; i--)
maxn = Max(maxn, (maxn^a[i]));
return maxn;
}
void clean() {
for (int i = ; i >= ; i--)
a[i] = ;
}
void copy(base b) {
for (int i = ; i >= ; i--)
a[i] = b.a[i];
}
void merge(base b) {
for (int i = ; i >= ; i--) {
insert(b.a[i]);
}
}
}ba[N+], tmp;
int n, q, u, v;
LL g[N+];
struct tt {
int to, next;
}edge[N*+];
int path[N+], top;
struct question {
int v, id, next;
}que[Q*+];
int pathq[N+], topq;
LL ans[Q+];
int size[N+], mx[N+], minsize, root;
bool vis[N+];
bool judge[N+]; void add(int u, int v) {
edge[++top].to = v;
edge[top].next = path[u];
path[u] = top;
}
void addq(int u, int v, int id) {
que[++topq].v = v;
que[topq].id = id;
que[topq].next = pathq[u];
pathq[u] = topq;
}
void get_size(int u, int fa) {
size[u] = , mx[u] = ;
for (int i = path[u]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to]) {
get_size(edge[i].to, u);
size[u] += size[edge[i].to];
mx[u] = Max(mx[u], size[edge[i].to]);
}
}
void get_root(int r, int u, int fa) {
mx[u] = Max(mx[u], size[r]-size[u]);
if (mx[u] < minsize) minsize = mx[u], root = u;
for (int i = path[u]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to])
get_root(r, edge[i].to, u);
}
void get_ans(int r, int u, int fa) {
ba[u].copy(ba[fa]);
ba[u].insert(g[u]);
for (int i = pathq[u]; i; i = que[i].next)
if (judge[que[i].v]) {
tmp.copy(ba[u]);
tmp.merge(ba[que[i].v]);
ans[que[i].id] = tmp.getmax();
}
else if (que[i].v == r) {
ans[que[i].id] = ba[u].getmax();
}
for (int i = path[u]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to])
get_ans(r, edge[i].to, u);
}
void get_update(int u, int fa) {
judge[u] = !judge[u];
for (int i = path[u]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to])
get_update(edge[i].to, u);
}
void doit(int x) {
minsize = INF;
get_size(x, );
get_root(x, x, );
vis[root] = ;
ba[root].clean();
ba[root].insert(g[root]);
for (int i = path[root]; i; i = edge[i].next)
if (!vis[edge[i].to]) {
get_ans(root, edge[i].to, root);
get_update(edge[i].to, root);
}
for (int i = path[root]; i; i = edge[i].next)
if (!vis[edge[i].to])
get_update(edge[i].to, root);
for (int i = path[root]; i; i = edge[i].next)
if (!vis[edge[i].to])
doit(edge[i].to);
}
void work() {
n = Read(), q = Read();
for (int i = ; i <= n; i++) scanf("%lld", &g[i]);
for (int i = ; i < n; i++) {
u = Read(), v = Read();
add(u, v), add(v, u);
}
for (int i = ; i <= q; i++) {
u = Read(), v = Read();
if (u != v) addq(u, v, i), addq(v, u, i);
else ans[i] = g[u];
}
doit();
for (int i = ; i <= q; i++) printf("%lld\n", ans[i]);
}
int main() {
st[] = ;
for (int i = ; i < ; i++)
st[i] = st[i-]<<;
work();
return ;
}

[SCOI 2016]幸运数字的更多相关文章

  1. bzoj 4568 [SCOI 2016] 幸运数字

    题目大意 给定一棵\(n\)个点的树,每个点有权值 \(q\)次询问树上路径中 每个点权值可选可不选的最大异或和 \(n\le 2*10^4,q\le 2*10^5,val[i]\le 2^{60}\ ...

  2. Scoi 2010 幸运数字

    [题目描述]在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888都是“幸运号码”!但是这种“幸 ...

  3. BZOJ 1853 【Scoi2010】 幸运数字

    Description 在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认 为,于是他定义自己的"幸运号码"是十进制表示中只包含数字6和8的那些号码,比如68,666,8 ...

  4. BZOJ 4568 幸运数字

    题目传送门 4568: [Scoi2016]幸运数字 Time Limit: 60 Sec Memory Limit: 256 MB Description A 国共有 n 座城市,这些城市由 n-1 ...

  5. BZOJ 1853: [Scoi2010]幸运数字

    1853: [Scoi2010]幸运数字 Time Limit: 2 Sec  Memory Limit: 64 MBSubmit: 2117  Solved: 779[Submit][Status] ...

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

    4568: [Scoi2016]幸运数字 Time Limit: 60 Sec  Memory Limit: 256 MBSubmit: 238  Solved: 113[Submit][Status ...

  7. 【BZOJ-1853&2393】幸运数字&Cirno的完美算数教室 容斥原理 + 爆搜 + 剪枝

    1853: [Scoi2010]幸运数字 Time Limit: 2 Sec  Memory Limit: 64 MBSubmit: 1817  Solved: 665[Submit][Status] ...

  8. BZOJ1853 [Scoi2010]幸运数字

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

  9. 【bzoj1853】 Scoi2010—幸运数字

    http://www.lydsy.com/JudgeOnline/problem.php?id=1853 (题目链接) 今天考试考了容斥,结果空知道结论却不会写→_→ 题意 求区间中不含6,8两个数字 ...

随机推荐

  1. Beta开始前准备

    Beta准备 1. 讨论组长是否重选的议题和结论. 经过讨论,我们认为,经过一段时间的磨合,现任组长是不需要更换的. 2. 下一阶段需要改进完善的功能. 增加关于征信的功能,贴近选题主题 美化界面,尽 ...

  2. choose the max from numbers, use scanf and if else (v1:21.9.2017,v2:23.9.2017)

    #include<stdio.h> int main(){ int a,b,c,max; printf("请输入一个数值: "); scanf("%d&quo ...

  3. MySql使用存储过程实现事务的提交或者回滚

    DELIMITER $$ DROP PROCEDURE IF EXISTS test_sp1 $$ CREATE PROCEDURE test_sp1( ) BEGIN ; ; START TRANS ...

  4. electron打包vue项目

    electron是什么 Electron是由Github开发,用HTML,CSS和JavaScript来构建跨平台桌面应用程序的一个开源库. Electron通过将Chromium和Node.js合并 ...

  5. signalR 消息推送

    业务情景一:上传报表,上传excel.如果excel的数据量很大,上万条,上十万条数据,那么这个上传请求必然是个耗时请求.用户上传之后,很关心上传的进度和结果. 业务情景二:站内消息提醒,实时有效地接 ...

  6. C# if判断语句执行顺序

    DataTable dt = null; )//不报错,因为先执行dt != null 成立时才执行dt.Rows.Count > 0 { } && dt != null)//报 ...

  7. 第1章 什么是TCP-IP

    第1章 什么是TCP-IP 什么是网络 网络是计算机或类似计算机的设备之间通过常用传输介质进行通信的集合.通常情况下,传输介质是绝缘的金属导线, 它用来在计算机之间携带电脉冲,介质也可以是电话线,甚至 ...

  8. Tomcat性能优化及JVM内存工作原理

    Java性能优化原则:代码运算性能.内存回收.应用配置(影响Java程序主要原因是垃圾回收,下面会重点介绍这方面) 代码层优化:避免过多循环嵌套.调用和复杂逻辑. Tomcat调优主要内容如下: 1. ...

  9. Python内置函数(49)——isinstance

    英文文档: isinstance(object, classinfo) Return true if the object argument is an instance of the classin ...

  10. Python-面向对象(二)-Day7

    1.字段 12.方法 43.属性 63.1.属性的基本使用 73.2.实例:对于主机列表 83.3.属性的两种定义方式 94.对于类的成员而言都有两种形式: 144.1.私有成员和公有成员的访问限制不 ...