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. 【R语言系列】read.table报错incomplete final line found by readTableHeader

    文件内容: id,SGBH,DMSM1,SGDO,SGFSSJ 1,310117620,伤人事故,上海市,2018-03-02 20:04:00 2,310117621,死亡事故,杭州市,2018-0 ...

  2. Java读取文件存储到mysql

    写了一批Lua脚本,要放到数据库里面,调用的时候进行计算,由于有太多lua脚本,就写了个程序来录入. 下面主要分三个部分: public static String readToString(Stri ...

  3. JavaScript(第十八天)【DOM基础】

    学习要点: 1.DOM介绍 2.查找元素 3.DOM节点 4.节点操作 DOM(Document Object Model)即文档对象模型,针对HTML和XML文档的API(应用程序接口).DOM描绘 ...

  4. 《构建之法》教学笔记——Python中的效能分析与几个问题

    <构建之法:现代软件工程>中第2章对效能分析进行了介绍,基于的工具是VSTS.由于我教授的学生中只有部分同学选修了C#,若采用书中例子讲解,学生可能理解起来比较困难.不过所有这些学生都学习 ...

  5. Build to win--来自小黄衫

    写在前面 首先非常荣幸.非常侥幸能以微弱的优势得到这次小黄衫,感谢各位老师同学的帮助,也谢谢来自<构建之法>团队的小黄衫赞助! 这次能够获得小黄衫,就像汪老师上课说的那样,其实,是一个积累 ...

  6. alpha-咸鱼冲刺day5

    一,合照 emmmmm.自然还是没有的. 二,项目燃尽图 三,项目进展 !!!QAQ可以做到跟数据库交互了!!!!先来撒花花!(然后继续甲板) 四,问题困难 日常啥都不会,百度真心玩一年. 还得自学n ...

  7. Build to win

    UPDATE:看到周筠老师的评论里的链接,那版式真的非常舒服.我想想模仿模仿他的布局来看看,虽然感觉做的也不是太好.另外对博客内容稍作修改. 一.获得小黄衫的感受 很幸运能够获得"领骑衫&q ...

  8. 敏捷冲刺每日报告——Day5

    1.情况简述 Alpha阶段第一次Scrum Meeting 敏捷开发起止时间 2017.10.29 00:00 -- 2017.10.30 00:00 讨论时间地点 2017.10.29晚6:00, ...

  9. 高校学生征信系统Postmortem结果

    Postmortem结果 设想和目标 1 我们的软件要解决什么问题?是否定义得很清楚?是否对典型用户和典型场景有清晰的描述? 我们的软件需要解决的问题是当前高校学生征信系统建设薄弱的问题,我们试图建立 ...

  10. Flask 学习 六 大型程序结构

    pip freeze >requirement.txt 自动生成版本号 pip install -r requirement.txt 自动下载对应的库 梳理结构 config.py #!/usr ...