[SCOI 2016]幸运数字
Description
Input
Output
输出需要包含 q 行,每行包含 1 个非负整数,表示这名旅行者可以保留的最大幸运值。
Sample Input
11 5 7 9
1 2
1 3
1 4
2 3
1 4
Sample Output
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]幸运数字的更多相关文章
- bzoj 4568 [SCOI 2016] 幸运数字
题目大意 给定一棵\(n\)个点的树,每个点有权值 \(q\)次询问树上路径中 每个点权值可选可不选的最大异或和 \(n\le 2*10^4,q\le 2*10^5,val[i]\le 2^{60}\ ...
- Scoi 2010 幸运数字
[题目描述]在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888都是“幸运号码”!但是这种“幸 ...
- BZOJ 1853 【Scoi2010】 幸运数字
Description 在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认 为,于是他定义自己的"幸运号码"是十进制表示中只包含数字6和8的那些号码,比如68,666,8 ...
- BZOJ 4568 幸运数字
题目传送门 4568: [Scoi2016]幸运数字 Time Limit: 60 Sec Memory Limit: 256 MB Description A 国共有 n 座城市,这些城市由 n-1 ...
- BZOJ 1853: [Scoi2010]幸运数字
1853: [Scoi2010]幸运数字 Time Limit: 2 Sec Memory Limit: 64 MBSubmit: 2117 Solved: 779[Submit][Status] ...
- 【BZOJ-4568】幸运数字 树链剖分 + 线性基合并
4568: [Scoi2016]幸运数字 Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 238 Solved: 113[Submit][Status ...
- 【BZOJ-1853&2393】幸运数字&Cirno的完美算数教室 容斥原理 + 爆搜 + 剪枝
1853: [Scoi2010]幸运数字 Time Limit: 2 Sec Memory Limit: 64 MBSubmit: 1817 Solved: 665[Submit][Status] ...
- BZOJ1853 [Scoi2010]幸运数字
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...
- 【bzoj1853】 Scoi2010—幸运数字
http://www.lydsy.com/JudgeOnline/problem.php?id=1853 (题目链接) 今天考试考了容斥,结果空知道结论却不会写→_→ 题意 求区间中不含6,8两个数字 ...
随机推荐
- RTMP规范协议
本文参照rtmp协议英文版,进行简单的协议分析 1.什么是RTMP 关于 Adobe 的实时消息协议(Real Time Messaging Protocol,RTMP),是一种多媒体的复用和分组的应 ...
- C语言程序设计(基础)- 第6周作业
一.PTA作业 完成PTA第六周作业中4个题目的思路列在博客中. 1.7-1 高速公路超速处罚 2.7-2 计算油费 3.7-3 比较大小 4.7-4 两个数的简单计算器 (必须使用switch结构实 ...
- 第1次作业:我与我的IT梦
第一部分:结缘计算机 1.1最美的风景,一直在路上 说实话以前没有想过自己将学习计算机这个专业,在大二之前,我还是教师教育学院的一名师范生,机缘巧合,赶上了学校允许师范专业的同学转到非师范专业,于是, ...
- 高级软件工程2017第6次作业——团队项目:Alpha阶段综合报告
1.版本测试报告 1.1在测试过程中总共发现了多少Bug?每个类别的Bug分别为多少个? Bug分类 Bug内容 Fixed 编辑博文时改变文字格式会刷新界面 Can't reproduced 无 N ...
- 201621123062《java程序设计》第13周作业总结
1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 思维导图: 2. 为你的系统增加网络功能(购物车.图书馆管理.斗地主等)-分组完成 为了让你的系统可以被多 ...
- git cherry-pick 整理
git cherry-pick可以选择某一个分支中的一个或几个commit(s)来进行操作.例如,假设我们有个稳定版本的分支,叫v2.0,另外还有个开发版本的分支v3.0,我们不能直接把两个分支合并, ...
- 新手入门 git
Git是目前世界上最先进的分布式版本控制系统 特点:高端大气上档次 什么是版本控制系统 系统自动记录文件改动 方便同事协作管理 不用自己管理一堆类似的文件了,也不需要把文件传来传去.如果想查看某次改动 ...
- java截取一个字符串正数或倒数某个特定字符前后的内容
取出正数第二个“.”后面的内容 public class TestCode { public static void main(String[] args) { String str ="2 ...
- JAVA_SE基础——10.变量的作用域
<pre name="code" class="java"> 上个月实在太忙了,从现在开始又可以静下心来写blog了. 变量的作用域指 可以使用此变 ...
- 3-51单片机WIFI学习(开发板8266底层源码介绍)
上一篇链接 http://www.cnblogs.com/yangfengwu/p/8743502.html 直接上源码:注意源码有两部分,第一部分是一开始的时候写在模块内部的,另一部分是存在手机内 ...