题面

题面

题解

题面意思非常明确:求树上一条链的最大异或和。

我们用倍增的思想。

将这条链分成2部分:x ---> lca , lca ---> y

分别求出这2个部分的线性基,然后合并,再求最大异或和。

所以我们现在只需要考虑如何在树上求一条无需拐弯的链的最大线性基。

考虑倍增。

我们预处理出f[i][j]表示从点i开始向上走\(2^j\)构成的链的线性基。至于只有点\(i\)一个点的线性基,我们可以在运算的时候特判一下处理。

暴力预处理后,我们就可以最多 合并3次 + 求LCA的复杂度 求出任意询问的答案了!

如果我们还是跟普通倍增一样暴力向上跳的话,是单次询问\(logn * 60 * 60\),所有询问的总复杂度\(q * logn * 60 * 60\),差不多都到百亿级别了!不知道为什么很多人用这种方法都过了。

所以我们考虑跟RMQ类似的思想,因为在线性基中插入重复串不会有什么影响,因此对于树上任意一条不带拐弯的链,我们完全可以拆分成2段长度至少为一半的链,然后合并即可。

虽然可能会有重复的部分,但是不会有影响。

所以就可以做到单次复杂度\(60 * 60 * 3\)啦,忽略3这个常数复杂度大概是7亿左右,时限6s基本还是可以勉强接受的范围。(这里的60其实是对一个longlong大小的数取log,因为比较大,所以不能忽略)

#include<bits/stdc++.h>
using namespace std;
#define R register int
#define LL long long
#define AC 21000
#define ac 40100 int n, m;
int Head[AC], Next[ac], date[ac], tot;
int dep[AC], fa[AC][15];
LL s[AC], ans; inline LL read()
{
LL x = 0;char c = getchar();
while(c > '9' || c < '0') c = getchar();
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
} inline void add(int f, int w)
{
date[++ tot] = w, Next[tot] = Head[f], Head[f] = tot;
date[++ tot] = f, Next[tot] = Head[w], Head[w] = tot;
} struct basis{
LL f[61]; inline void clear() {memset(f, 0, sizeof(f));}
inline void ins(LL x)
{
LL maxn = 1LL << 60;
for(R i = 60; ~i; i --, maxn >>= 1)
{
if(!(x & maxn)) continue;
if(!f[i]) {f[i] = x; break;}
else x ^= f[i];
}
} inline void merge(basis x){for(R i = 0; i <= 60; i ++) ins(x.f[i]);}
}f[AC][15], a, b; void dfs(int x)
{
f[x][0].ins(s[x]), f[x][0].ins(s[fa[x][0]]);//直接按常规方法处理,使用的时候特判掉
for(R i = 1; i <= 14; i ++)
{
fa[x][i] = fa[fa[x][i - 1]][i - 1];
f[x][i] = f[x][i - 1], f[x][i].merge(f[fa[x][i - 1]][i - 1]);
}
for(R i = Head[x]; i; i = Next[i])
{
int now = date[i];
if(now == fa[x][0]) continue;
fa[now][0] = x, dep[now] = dep[x] + 1, dfs(now);
}
} inline int LCA(int x, int y)
{
if(dep[x] < dep[y]) swap(x, y);
for(R i = 14; i >= 0; i --)
if(dep[fa[x][i]] >= dep[y]) x = fa[x][i];
for(R i = 14; i >= 0; i --)
if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
if(x == y) return x;
else return fa[x][0];
} inline int kth(int x, int k)
{
int lim = dep[x] - k;
for(R i = 14; i >= 0; i --)
if(dep[fa[x][i]] >= lim) x = fa[x][i];
return x;
} void cal(int x, int y)
{
int lca = LCA(x, y), len1 = dep[x] - dep[lca], len2 = dep[y] - dep[lca];
a.clear(), b.clear();
if(!len1) a.ins(s[x]);
else
{
LL tmp = 1, cnt = 0;
for(R i = 0; i <= 60; i ++, tmp <<= 1, ++ cnt) if((tmp << 1) > len1) break;
a = f[x][cnt], a.merge(f[kth(x, len1 - tmp)][cnt]);
}
if(!len2) b.ins(s[y]);
else
{
LL tmp = 1, cnt = 0;
for(R i = 0; i <= 60; i ++, tmp <<= 1, ++ cnt) if((tmp << 1) > len2) break;
b = f[y][cnt], b.merge(f[kth(y, len2 - tmp)][cnt]);
}
a.merge(b);
} void pre()
{
n = read(), m = read(), fa[1][0] = dep[1] = 1;
for(R i = 1; i <= n; i ++) s[i] = read();
for(R i = 1; i < n; i ++) add(read(), read());
} void work()
{
for(R i = 1; i <= m; i ++)
{
cal(read(), read()), ans = 0;
for(R j = 60; ~j; j --)
if((ans ^ a.f[j]) > ans) ans ^= a.f[j];
printf("%lld\n", ans);
}
} int main()
{
// freopen("in.in", "r", stdin);
pre();
dfs(1);//建倍增数组
work();
// fclose(stdin);
return 0;
}

[SCOI2016]幸运数字 线性基的更多相关文章

  1. BZOJ 4568: [Scoi2016]幸运数字 [线性基 倍增]

    4568: [Scoi2016]幸运数字 题意:一颗带点权的树,求树上两点间异或值最大子集的异或值 显然要用线性基 可以用倍增的思想,维护每个点向上\(2^j\)个祖先这些点的线性基,求lca的时候合 ...

  2. 洛谷P3292 [SCOI2016]幸运数字 线性基+倍增

    P3292 [SCOI2016]幸运数字 传送门 题目描述 A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在 ...

  3. 洛谷P3292 [SCOI2016] 幸运数字 [线性基,倍增]

    题目传送门 幸运数字 题目描述 A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的 ...

  4. bzoj4568 [Scoi2016]幸运数字 线性基+树链剖分

    A 国共有 n 座城市,这些城市由 n-1 条道路相连,使得任意两座城市可以互达,且路径唯一.每座城市都有一个 幸运数字,以纪念碑的形式矗立在这座城市的正中心,作为城市的象征.一些旅行者希望游览 A ...

  5. P3292 [SCOI2016]幸运数字 线性基

    正解:线性基+倍增 解题报告: 先放下传送门QAQ 然后这题,其实没什么太大的技术含量,,,?就几个知识点套在一起,除了代码长以外没任何意义,主要因为想复习下线性基的题目所以还是写下,,, 随便写下思 ...

  6. BZOJ.4516.[SCOI2016]幸运数字(线性基 点分治)

    题目链接 线性基可以\(O(log^2)\)暴力合并.又是树上路径问题,考虑点分治. 对于每个点i求解 LCA(u,v)==i 时的询问(u,v),只需求出这个点到其它点的线性基后,暴力合并. LCA ...

  7. BZOJ4568: [Scoi2016]幸运数字(线性基 倍增)

    题意 题目链接 Sol 线性基是可以合并的 倍增维护一下 然后就做完了?? 喵喵喵? // luogu-judger-enable-o2 #include<bits/stdc++.h> # ...

  8. BZOJ 4568 [Scoi2016]幸运数字 ——线性基 倍增

    [题目分析] 考虑异或的最大值,维护线性基就可以了. 但是有多次的询问,树剖或者倍增都可以. 想了想树剖动辄数百行的代码. 算了,我还是写倍增吧. 注:被位运算和大于号的优先级坑了一次,QaQ [代码 ...

  9. P3292 [SCOI2016]幸运数字 [线性基+倍增]

    线性基+倍增 // by Isaunoya #include <bits/stdc++.h> using namespace std; #define rep(i, x, y) for ( ...

随机推荐

  1. LVS入门篇(二)之LVS基础

    1. LVS介绍 LVS是Linux虚拟服务器(LinuxVirtualServers),使用负载均衡技术将多台服务器组成一个虚拟服务器.它为适应快速增长的网络访问需求提供了一个负载能力易于扩展,而价 ...

  2. NB-IOT模组指令AT+NMSTATUS和AT+CGPADDR对比

    1. AT+NMSTATUS,这个指令是用来查询模块在IOT平台的注册情况.注册指的是lwm2m协议里面的注册机制,详细可以参考lwm2m协议. 2. AT+MREGSWT,设置重启之后,自动启动注册 ...

  3. idea alt+enter导包时被锁定导某一个包时的解决方法

    在只有一个包指向的时候,把光标放在Test这种字符之间的话 就会直接导这个 所以把光标放在最后就可以导别的了

  4. 【JUC源码解析】CountDownLatch

    简介 CountDownLatch,是一个同步器,允许一个或多个线程等待,直到一组操作在其他线程中完成. 概述 初始CountDownLatch时,会给定count,await方法会阻塞,直到coun ...

  5. javaweb(十四)——JSP原理

    一.什么是JSP? JSP全称是Java Server Pages,它和servle技术一样,都是SUN公司定义的一种用于开发动态web资源的技术. JSP这门技术的最大的特点在于,写jsp就像在写h ...

  6. Power Designer逆向工程导入Oracle表,转为模型加注释

    1.打开PowerDesigner ——文件——Reverse Engineer——DataBase 2.选择所要连接数据库版本,此处使用的是oracle version 11g. 3.点击红色区域, ...

  7. Tensorflow基本开发架构

    Tensorflow基本开发架构 先说句题外话, 这段时间一直研究爬虫技术,主要目的是为将来爬取训练数据做准备,同时学习python编程.这一研究才发现,python的开发资源实在是太丰富了,所有你能 ...

  8. 剑指offer-数值的整数方

    数值的整数方 一.问题描述 给定一个double类型的浮点数base和int类型的整数exponent.求base的exponent次方. 二.算法思路 按照指数Exp的情况进行讨论. Exp> ...

  9. 一个小时搭建一个全栈 Web 应用框架

    把想法变为现实的能力是空想家与实干家的区别.不管你是在一家跨国公司工作,还是正在为自己的创业公司而努力,那些有能力将创意转化为真正产品的人,都具有宝贵的技能并拥有明显的实力.如果你能在不到一个小时的时 ...

  10. python3【基础】-集合

    集合( set):把不同的元素组成一起形成集合,是python基本的数据类型. 集合元素(set elements):组成集合的成员(不可重复) class set(object) | set() - ...